/// <summary> /// Returns true if a unique plane was found i.e. the given points are not coincident or colinear. /// </summary> /// <param name="points"></param> /// <param name="start"></param> /// <param name="direction"></param> /// <param name="tolerance"></param> /// <returns></returns> public static bool FitLineToPoints(IEnumerable <Vector3d> points, Vector3d start, out Vector3d direction, double tolerance = D.ZeroTolerance) { // impl refs // https://www.geometrictools.com/Documentation/LeastSquaresFitting.pdf var covm = Matrix3d.CreateCovariance(points, start); Matrix3d.Decompose.EigenSymmetric(ref covm, out Matrix3d vecs, out Vector3d vals, tolerance); direction = vecs.Column0; // Check for degeneracy -> if 1st eigenvalue is 0, then points are coincident return(Math.Abs(vals.X) >= tolerance); }
/// <summary> /// Returns true if a unique plane was found i.e. the given points are not coincident or colinear. /// </summary> /// <param name="points"></param> /// <param name="origin"></param> /// <param name="normal"></param> /// <param name="tolerance"></param> /// <returns></returns> public static bool FitPlaneToPoints(IEnumerable <Vector3d> points, Vector3d origin, out Vector3d normal, double tolerance = D.ZeroTolerance) { // impl refs // https://www.geometrictools.com/Documentation/LeastSquaresFitting.pdf // http://www.ilikebigbits.com/blog/2017/9/24/fitting-a-plane-to-noisy-points-in-3d var covm = Matrix3d.CreateCovariance(points, origin); Matrix3d.Decompose.EigenSymmetric(ref covm, out Matrix3d vecs, out Vector3d vals, tolerance); normal = vecs.Column2; // Check for degeneracy -> if 2nd eigenvalue is 0, the points are colinear at best return(Math.Abs(vals.Y) >= tolerance); }
/// <summary> /// Returns 0 if the given points are coincident, 1 if they're colinear, 2 if they're coplanar, and 3 otherwise. /// </summary> /// <param name="points"></param> /// <param name="origin"></param> /// <param name="xAxis"></param> /// <param name="yAxis"></param> /// <param name="tolerance"></param> /// <returns></returns> public static int PrincipalComponentAnalysis(IEnumerable <Vector3d> points, out Vector3d origin, out Vector3d xAxis, out Vector3d yAxis, double tolerance = D.ZeroTolerance) { origin = points.Mean(); var covm = Matrix3d.CreateCovariance(points, origin); Matrix3d.Decompose.EigenSymmetric(ref covm, out Matrix3d vecs, out Vector3d vals, tolerance); xAxis = vecs.Column0; yAxis = vecs.Column1; return (Math.Abs(vals.X) < tolerance ? 0 : Math.Abs(vals.Y) < tolerance ? 1 : Math.Abs(vals.Z) < tolerance ? 2 : 3); }