public override HitResult GetHitResult(Ray ray) { var a = Vector3.Dot(VerticalVector, ray.Direction); if (Math.Abs(a) < float.Epsilon) { return new HitResult { Hit = false } } ; var b = Vector3.Dot(VerticalVector, ray.Origin) - VerticalVector.Length() * DistanceFromOrigin; var res = -b / a; if (res <= 0) { return new HitResult { Hit = false } } ; var hitPoint = ray.Origin + res * ray.Direction; var maybeNorm = Vector3.Normalize(VerticalVector); return(new HitResult { Hit = true, HitPoint = hitPoint, HitNorm = Vector3.Dot(maybeNorm, ray.Direction) < 0 ? maybeNorm : -maybeNorm }); } } }
/// <summary> /// Calculates eigenvectors (loads) and the corresponding eigenvalues (scores) /// by means of the NIPALS algorithm /// </summary> /// <param name="X">The matrix to which the decomposition is applied to. A row of the matrix is one spectrum (or a single measurement giving multiple resulting values). The different rows of the matrix represent /// measurements under different conditions.</param> /// <param name="numFactors">The number of factors to be calculated. If 0 is provided, factors are calculated until the provided accuracy is reached. </param> /// <param name="accuracy">The relative residual variance that should be reached.</param> /// <param name="factors">Resulting matrix of factors. You have to provide a extensible matrix of dimension(0,0) as the vertical score vectors are appended to the matrix.</param> /// <param name="loads">Resulting matrix consiting of horizontal load vectors (eigenspectra). You have to provide a extensible matrix of dimension(0,0) here.</param> /// <param name="residualVarianceVector">Residual variance. Element[0] is the original variance, element[1] the residual variance after the first factor subtracted and so on. You can provide null if you don't need this result.</param> public static void NIPALS_HO( IMatrix X, int numFactors, double accuracy, IRightExtensibleMatrix factors, IBottomExtensibleMatrix loads, IBottomExtensibleMatrix residualVarianceVector) { // first center the matrix //MatrixMath.ColumnsToZeroMean(X, null); double originalVariance = Math.Sqrt(MatrixMath.SumOfSquares(X)); if(null!=residualVarianceVector) residualVarianceVector.AppendBottom(new MatrixMath.Scalar(originalVariance)); IMatrix l = new HorizontalVector(X.Columns); IMatrix t_prev = null; IMatrix t = new VerticalVector(X.Rows); int maxFactors = numFactors<=0 ? X.Columns : Math.Min(numFactors,X.Columns); for(int nFactor=0; nFactor<maxFactors; nFactor++) { //l has to be a horizontal vector // 1. Guess the transposed Vector l_transp, use first row of X matrix if it is not empty, otherwise the first non-empty row int rowoffset=0; do { Submatrix(X,l,rowoffset,0); // l is now a horizontal vector rowoffset++; } while(IsZeroMatrix(l) && rowoffset<X.Rows); for(int iter=0;iter<500;iter++) { // 2. Calculate the new vector t for the factor values MultiplySecondTransposed(X,l,t); // t = X*l_t (t is a vertical vector) // Compare this with the previous one if(t_prev!=null && IsEqual(t_prev,t,1E-9)) break; // 3. Calculate the new loads MultiplyFirstTransposed(t,X,l); // l = t_tr*X (gives a horizontal vector of load (= eigenvalue spectrum) // normalize the (one) row NormalizeRows(l); // normalize the eigenvector spectrum // 4. Goto step 2 or break after a number of iterations if(t_prev==null) t_prev = new VerticalVector(X.Rows); Copy(t,t_prev); // stores the content of t in t_prev } // Store factor and loads factors.AppendRight(t); loads.AppendBottom(l); // 5. Calculate the residual matrix X = X - t*l SubtractProductFromSelf(t,l,X); // X is now the residual matrix // if the number of factors to calculate is not provided, // calculate the norm of the residual matrix and compare with the original // one if(numFactors<=0 || null!=residualVarianceVector) { double residualVariance = Math.Sqrt(MatrixMath.SumOfSquares(X)); residualVarianceVector.AppendBottom(new MatrixMath.Scalar(residualVariance)); if(residualVariance<=accuracy*originalVariance) { break; } } } // for all factors } // end NIPALS