/*
* /// <summary>
* /// A comparator which compares only the X value of the point
* /// </summary>
* private class XValueOfPointComparator : IComparer<PointF>
* {
* public int Compare(PointF p1, PointF p2)
* {
* return p1.X.CompareTo(p2.X);
* }
* }
*
* /// <summary>
* /// Perform a first degree interpolation to lookup the y coordinate given the x coordinate
* /// </summary>
* /// <param name="points">The collection of points. Must be sorted by the x value.</param>
* /// <param name="index">the x coordinate</param>
* /// <returns>the y coordinate as the result of the first degree interpolation</returns>
* public static float FirstDegreeInterpolate(PointF[] points, float index)
* {
* XValueOfPointComparator comparator = new XValueOfPointComparator();
* int idx = Array.BinarySearch<PointF>(points, new PointF(index, 0.0f), comparator);
*
* if (idx >= 0) // an exact index is matched
* return points[idx].Y;
*
* // the index fall into a range, in this case we do interpolation
* idx = -idx;
*
* if (idx == 1)
* // the specific index is smaller than all indexes
* idx = 0;
* else if (idx == points.Length + 1)
* // the specific index is larger than all indexes
* idx = points.Length - 2;
* else
* idx -= 2;
*
* LineSegment2DF line = new LineSegment2DF(points[idx], points[idx + 1]);
* return line.YByX(index);
* }
*
* /// <summary>
* /// Perform a first degree interpolation to lookup the y coordinates given the x coordinates
* /// </summary>
* /// <param name="points">The collection of points, Must be sorted by x value</param>
* /// <param name="indexes">the x coordinates</param>
* /// <returns>The y coordinates as the result of the first degree interpolation</returns>
* public static float[] FirstDegreeInterpolate(PointF[] points, float[] indexes)
* {
* return Array.ConvertAll<float, float>(
* indexes,
* delegate(float d) { return FirstDegreeInterpolate(points, d); });
* }*/
/// <summary>
/// Fit a line to the points collection
/// </summary>
/// <param name="points">The points to be fitted</param>
/// <param name="type">The type of the fitting</param>
/// <param name="normalizedDirection">The normalized direction of the fitted line</param>
/// <param name="aPointOnLine">A point on the fitted line</param>
public static void Line2DFitting(PointF[] points, CvEnum.DIST_TYPE type, out PointF normalizedDirection, out PointF aPointOnLine)
{
float[] data = new float[6];
IntPtr seq = Marshal.AllocHGlobal(StructSize.MCvSeq);
IntPtr block = Marshal.AllocHGlobal(StructSize.MCvSeqBlock);
GCHandle handle = GCHandle.Alloc(points, GCHandleType.Pinned);
CvInvoke.cvMakeSeqHeaderForArray(
CvInvoke.CV_MAKETYPE((int)CvEnum.MAT_DEPTH.CV_32F, 2),
StructSize.MCvSeq,
StructSize.PointF,
handle.AddrOfPinnedObject(),
points.Length,
seq,
block);
CvInvoke.cvFitLine(seq, type, 0.0, 0.01, 0.01, data);
handle.Free();
Marshal.FreeHGlobal(seq);
Marshal.FreeHGlobal(block);
normalizedDirection = new PointF(data[0], data[1]);
aPointOnLine = new PointF(data[2], data[3]);
}