/// <summary> /// Creates a raster mapper from raster coordinates. /// </summary> /// <param name="mode">The raster mapping mode.</param> /// <param name="coordinates">The list of coordinates.</param> /// <returns>The raster mapper created by linear interpolation of the coordinates.</returns> /// <exception cref="System.ArgumentNullException">The array of coordinates is null.</exception> /// <exception cref="System.ArgumentException"> /// The number of coordinates with distinct column index is less than 2. /// or /// The number of coordinates with distinct row index is less than 2. /// </exception> public static RasterMapper FromCoordinates(RasterMapMode mode, IList <RasterCoordinate> coordinates) { if (coordinates == null) { throw new ArgumentNullException("The list of coordinates is null.", "coordinates"); } if (coordinates.Select(coordinate => coordinate.ColumnIndex).Distinct().Count() < 2) { throw new ArgumentException("The number of coordinates with distinct column index is less than 2.", "coordinates"); } if (coordinates.Select(coordinate => coordinate.RowIndex).Distinct().Count() < 2) { throw new ArgumentException("The number of coordinates with distinct row index is less than 2.", "coordinates"); } // compute linear equation system in both dimensions Int32[] columnIndices = coordinates.Select(coordinate => coordinate.ColumnIndex).Distinct().ToArray(); Int32[] rowIndices = coordinates.Select(coordinate => coordinate.ColumnIndex).Distinct().ToArray(); Matrix matrix = new Matrix(coordinates.Count, 3); Vector vectorX = new Vector(coordinates.Count); Vector vectorY = new Vector(coordinates.Count); for (Int32 coordinateIndex = 0; coordinateIndex < coordinates.Count; coordinateIndex++) { matrix[coordinateIndex, 0] = coordinates[coordinateIndex].ColumnIndex; matrix[coordinateIndex, 1] = coordinates[coordinateIndex].RowIndex; matrix[coordinateIndex, 2] = 1; vectorX[coordinateIndex] = coordinates[coordinateIndex].Coordinate.X; vectorY[coordinateIndex] = coordinates[coordinateIndex].Coordinate.Y; } // solve equation using least squares method Vector resultX = LUDecomposition.SolveEquation(matrix.Transpone() * matrix, matrix.Transpone() * vectorX); Vector resultY = LUDecomposition.SolveEquation(matrix.Transpone() * matrix, matrix.Transpone() * vectorY); // merge the results into a matrix Matrix transformation = new Matrix(4, 4); transformation[0, 0] = resultX[0]; transformation[0, 1] = resultX[1]; transformation[0, 3] = resultX[2]; transformation[1, 0] = resultY[0]; transformation[1, 1] = resultY[1]; transformation[1, 3] = resultY[2]; transformation[3, 3] = 1; return(new RasterMapper(mode, transformation)); }
/// <summary> /// Creates a general (not invertible) polynomial transformation. /// </summary> /// <param name="degree">The degree of the polynomial.</param> /// <param name="sourceEvaluationCoordinate">The source evaluation coordinate.</param> /// <param name="sourceCoordinates">The source coordinates.</param> /// <param name="targetEvaluationCoordinate">The target evaluation coordinate.</param> /// <param name="targetCoordinates">The target coordinates.</param> /// <returns>The general polynomial transformation created from the specified coordinates.</returns> /// <exception cref="System.ArgumentException"> /// The degree is not valid. /// or /// The amount of source coordinates is insufficient for the specified degree. /// or /// The amount of target coordinates is insufficient for the specified degree. /// or /// The amount of source and target coordinates does not match. /// </exception> /// <exception cref="System.ArgumentNullException"> /// The list of source coordinates is null. /// or /// The list of target coordinates is null. /// </exception> public static GeneralPolynomialTransformation CreateGeneralTransformation(Int32 degree, Coordinate sourceEvaluationCoordinate, IList <Coordinate> sourceCoordinates, Coordinate targetEvaluationCoordinate, IList <Coordinate> targetCoordinates) { if (degree < 1) { throw new ArgumentException("The degree is not valid.", "degree"); } Int32 size = Convert.ToInt32(Calculator.Sum(1, degree + 1)); if (sourceCoordinates == null) { throw new ArgumentNullException("The list of source coordinates is null.", "sourceCoordinates"); } if (sourceCoordinates.Count < size) { throw new ArgumentException("The amount of source coordinates is insufficient for the specified degree.", "sourceCoordinates"); } if (targetCoordinates == null) { throw new ArgumentNullException("The list of target coordinates is null.", "targetCoordinates"); } if (targetCoordinates.Count < size) { throw new ArgumentException("The amount of target coordinates is insufficient for the specified degree.", "targetCoordinates"); } if (sourceCoordinates.Count != targetCoordinates.Count) { throw new ArgumentException("The amount of source and target coordinates does not match.", "targetCoordinates"); } // compute scaling factors Double sourceScalingFactor = 2 / (sourceCoordinates.Select(coordinate => coordinate.X).Average() + sourceCoordinates.Select(coordinate => coordinate.Y).Average()); Double targetScalingFactor = 2 / (targetCoordinates.Select(coordinate => coordinate.X).Average() + targetCoordinates.Select(coordinate => coordinate.Y).Average()); Matrix sourceMatrixA = new Matrix(size, size); Matrix sourceMatrixB = new Matrix(size, size); Vector targetVectorX = new Vector(size); Vector targetVectorY = new Vector(size); // compute coordinates Int32 l = 0; for (Int32 i = 0; i < sourceCoordinates.Count; i++) { sourceMatrixA[i, 0] = 1; sourceMatrixB[i, 0] = 1; l = 1; for (Int32 j = 1; j <= degree; j++) { Int32 m = Convert.ToInt32(Calculator.Sum(1, j + 1)) - Convert.ToInt32(Calculator.Sum(1, j)); for (Int32 k = 0; k < m; k++) { Double u = (sourceCoordinates[i].X - sourceEvaluationCoordinate.X) * sourceScalingFactor; Double v = (sourceCoordinates[i].Y - sourceEvaluationCoordinate.Y) * sourceScalingFactor; sourceMatrixA[i, l] = Calculator.Pow(u, j - k) * Calculator.Pow(v, k); sourceMatrixB[i, l] = Calculator.Pow(u, j - k) * Calculator.Pow(v, k); l++; } } targetVectorX[i] = (targetCoordinates[i].X - targetEvaluationCoordinate.X) * targetScalingFactor; targetVectorY[i] = (targetCoordinates[i].Y - targetEvaluationCoordinate.Y) * targetScalingFactor; } // compute coefficients Vector resultA = LUDecomposition.SolveEquation(sourceMatrixA, targetVectorX); Vector resultB = LUDecomposition.SolveEquation(sourceMatrixB, targetVectorY); // compute parameters Dictionary <CoordinateOperationParameter, Object> parameters = GenerateParameters(degree, sourceEvaluationCoordinate, targetEvaluationCoordinate, sourceScalingFactor, targetScalingFactor, resultA, resultB); return(new GeneralPolynomialTransformation(degree, parameters)); }