/// <summary> /// Initializes a new instance of the /// MapAround.CoordinateSystems.Transformations.RubberSheetingTransform /// </summary> /// <param name="sourceControlPoints">An array containing coordinates of the source control points</param> /// <param name="destinationControlPoints">An array containing coordinates of the destination control points</param> public RubberSheetingTransform(ICoordinate[] sourceControlPoints, ICoordinate[] destinationControlPoints) { if (sourceControlPoints == null) throw new ArgumentNullException("sourceControlPoints"); if (destinationControlPoints == null) throw new ArgumentNullException("destinationControlPoints"); if (sourceControlPoints.Length < 3) throw new ArgumentException("Number of source control points should be equal or greater than three.", "sourceControlPoints"); if (destinationControlPoints.Length < 3) throw new ArgumentException("Number of destination control points should be equal or greater than three.", "destinationControlPoints"); if (destinationControlPoints.Length != sourceControlPoints.Length) throw new ArgumentException("Number of destination control points and source control points should be equal"); _sourceControlPoints = sourceControlPoints; _destinationControlPoints = destinationControlPoints; _affineTransformPointsIndicies = calculateOptimalAffineTransformPoints(); _optimalAffineTransform = new Affine( getAffineTransformMatrix( _sourceControlPoints[_affineTransformPointsIndicies[0]], _sourceControlPoints[_affineTransformPointsIndicies[1]], _sourceControlPoints[_affineTransformPointsIndicies[2]], _destinationControlPoints[_affineTransformPointsIndicies[0]], _destinationControlPoints[_affineTransformPointsIndicies[1]], _destinationControlPoints[_affineTransformPointsIndicies[2]] )); calcControlPointsShifts(); }
private int[] calculateOptimalAffineTransformPoints() { int[] result = new int[3]; double minNorm = double.MaxValue; for (int i1 = 0; i1 < _sourceControlPoints.Length - 2; i1++) for (int i2 = i1 + 1; i2 < _sourceControlPoints.Length - 1; i2++) for (int i3 = i2 + 1; i3 < _sourceControlPoints.Length; i3++) { ICoordinate p01 = _sourceControlPoints[i1]; ICoordinate p02 = _sourceControlPoints[i2]; ICoordinate p03 = _sourceControlPoints[i3]; ICoordinate p11 = _destinationControlPoints[i1]; ICoordinate p12 = _destinationControlPoints[i2]; ICoordinate p13 = _destinationControlPoints[i3]; Matrix m = getAffineTransformMatrix(p01, p02, p03, p11, p12, p13); if (m != null) { ICoordinate[] tempPoints = new ICoordinate[_sourceControlPoints.Length]; for (int i = 0; i < _sourceControlPoints.Length; i++) tempPoints[i] = (ICoordinate)_sourceControlPoints[i].Clone(); Affine affineTransform = new Affine(m); for (int i = 0; i < tempPoints.Length; i++) tempPoints[i] = PlanimetryEnvironment.NewCoordinate( affineTransform.Transform(tempPoints[i].Values())); double currentNorm = 0; for (int i = 0; i < tempPoints.Length; i++) currentNorm += PlanimetryAlgorithms.Distance(_destinationControlPoints[i], PlanimetryEnvironment.NewCoordinate(tempPoints[i].X, tempPoints[i].Y)); if (currentNorm < minNorm) { minNorm = currentNorm; result[0] = i1; result[1] = i2; result[2] = i3; } } } return result; }
/// <summary> /// Combines this affine transfor with the other. /// <remarks> /// The result of the combined transformation is equivalent to the result /// of successive application of transformations. Preferable to use this /// form of combination, not ConcatenatedTransform, because /// ConcatenatedTransform applies each transformation consistently, and /// CombineWith method calculates the resulting transformation matrix. /// </remarks> /// </summary> /// <param name="other">An affine transform to combine</param> public void CombineWith(Affine other) { _matrix = _matrix.Multiply(other._matrix); if (_inverseMatrix != null) _inverseMatrix = _matrix.GetInverseMatrix(); }