private static Sym3x3 ComputeWeightedCovariance(int n, Vector3F[] points, float[] weights)
        {
            // compute the centroid
              float total = 0.0f;
              Vector3F centroid = new Vector3F(0.0f);
              for (int i = 0; i < n; ++i)
              {
            total += weights[i];
            centroid += weights[i] * points[i];
              }
              if (total > float.Epsilon)
            centroid /= total;

              // accumulate the covariance matrix
              Sym3x3 covariance = new Sym3x3();
              for (int i = 0; i < n; ++i)
              {
            Vector3F a = points[i] - centroid;
            Vector3F b = weights[i] * a;

            covariance.M0 += a.X * b.X;
            covariance.M1 += a.X * b.Y;
            covariance.M2 += a.X * b.Z;
            covariance.M3 += a.Y * b.Y;
            covariance.M4 += a.Y * b.Z;
            covariance.M5 += a.Z * b.Z;
              }

              // return it
              return covariance;
        }
        private static Vector3F ComputePrincipleComponent(Sym3x3 matrix)
        {
            Vector4F row0 = new Vector4F(matrix.M0, matrix.M1, matrix.M2, 0.0f);
              Vector4F row1 = new Vector4F(matrix.M1, matrix.M3, matrix.M4, 0.0f);
              Vector4F row2 = new Vector4F(matrix.M2, matrix.M4, matrix.M5, 0.0f);
              Vector4F v = Vector4F.One;

              const int POWER_ITERATION_COUNT = 8;
              for (int i = 0; i < POWER_ITERATION_COUNT; ++i)
              {
            // matrix multiply
            Vector4F w = row0 * v.X;
            w = MultiplyAdd(row1, v.Y, w);
            w = MultiplyAdd(row2, v.Z, w);

            // get max component from xyz in all channels
            Vector4F a = new Vector4F(Math.Max(w.X, Math.Max(w.Y, w.Z)));

            // divide through and advance
            v = w / a;
              }

              return v.XYZ;
        }