public static Line2 FitLine(IList <Vector2> points) { var n = points.Count; if (n < 2) { throw new ArgumentException("At least two points are required to fit a line."); } var x = new double[n, 2]; var centroid = Vector2.Centroid(points); for (int i = 0; i < n; i++) { x[i, 0] = points[i].X - centroid.X; x[i, 1] = points[i].Y - centroid.Y; } double[] w; double[,] u, vt; const int uNeeded = 0; // don't need left singular vectors const int vtNeeded = 1; // need first set of right singular vectors const int extraMemoryAllowedSetting = 2; // it's ok to use more memory for performance alglib.rmatrixsvd(x, n, 2, uNeeded, vtNeeded, extraMemoryAllowedSetting, out w, out u, out vt); // because alglib.rmatrixsvd promises to return singular values, w, in descending order, we can be sure that w[0] is the greatest const int IndexOfGreatestSingularValue = 0; var a = vt[IndexOfGreatestSingularValue, 0]; var b = vt[IndexOfGreatestSingularValue, 1]; var direction = new Vector2(a, b); return(Line2.FromPointAndDirection(centroid, direction)); }