/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.referencing.operation.builder; import org.geotools.referencing.operation.matrix.GeneralMatrix; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.geometry.MismatchedReferenceSystemException; import java.util.List; // J2SE and extensions import javax.vecmath.MismatchedSizeException; /** * Builds {@linkplain org.opengis.referencing.operation.MathTransform * MathTransform} setup as Similar transformation from a list of {@linkplain * org.geotools.referencing.operation.builder.MappedPosition MappedPosition}. * The The calculation uses least square method. The similar transform * equation:
                                                  
 *  [ x']   [  a -b  Tx  ] [ x ]   [ a*x - b*y + Tx ]
 *  [ y'] = [  b  a  Ty  ] [ y ] = [ b*x + a*y + Ty ] 
In the case * that we have more identical points we can write it like this (in Matrix): *
                                           
 *  [ x'1 ]      [ x1 -y1  1 0 ]   [ a  ]
 *  [ x'2 ]      [ x2 -y2  1 0 ]   [ b  ]
 *  [  .  ]      [      .      ]   [ Tx ]                          
 *  [  .  ]      [      .      ] * [ Ty ]                          
 *  [ x'n ]   =  [ xn  yn  1 0 ]   
 *  [ y'1 ]      [ y1  x1  0 1 ]   
 *  [ y'2 ]      [ y2  x2  0 1 ]  
 *  [  .  ]      [      .      ]                                      
 *  [  .  ]      [      .      ]                                    
 *  [ y'n ]      [ yn xn  0  1 ]     
 *    x' = A*m  
Using the least square method we get this result: *
* m = (ATA)-1 ATx'
* * @since 2.4 * * * @source $URL$ * @version $Id$ * @author Jan Jezek */ public class SimilarTransformBuilder extends ProjectiveTransformBuilder { /** * Creates SimilarTransformBuilder for the set of properties. The {@linkplain java.util.List List} of {@linkplain * org.geotools.referencing.operation.builder.MappedPosition MappedPosition} is expected. * * @param vectors list of {@linkplain * org.geotools.referencing.operation.builder.MappedPosition MappedPosition} */ public SimilarTransformBuilder(List vectors) throws MismatchedSizeException, MismatchedDimensionException, MismatchedReferenceSystemException { super.setMappedPositions(vectors); } protected void fillAMatrix() { super.A = new GeneralMatrix(2 * getSourcePoints().length, 4); int numRow = getSourcePoints().length * 2; // Creates X matrix for (int j = 0; j < (numRow / 2); j++) { A.setRow(j, new double[] { getSourcePoints()[j].getCoordinate()[0], -getSourcePoints()[j].getCoordinate()[1], 1, 0 }); } for (int j = numRow / 2; j < numRow; j++) { A.setRow(j, new double[] { getSourcePoints()[j - (numRow / 2)].getCoordinate()[1], getSourcePoints()[j - (numRow / 2)].getCoordinate()[0], 0, 1 }); } } /** * Returns the minimum number of points required by this builder, * which is 2. * * @return Returns the minimum number of points required by this builder, * which is 2. */ public int getMinimumPointCount() { return 2; } /** * Returns the matrix for Projective transformation setup as * Affine. The M matrix looks like this: *
                                                       
     * [  a  -b  Tx  ]                           
     * [  b   a  Ty  ]                              
     * [  0   0  1   ]                                                                   
     * 
* * @return Matrix M. */ protected GeneralMatrix getProjectiveMatrix() { GeneralMatrix M = new GeneralMatrix(3, 3); double[] param = calculateLSM(); double[] m0 = { param[0], -param[1], param[2] }; double[] m1 = { param[1], param[0], param[3] }; double[] m2 = { 0, 0, 1 }; M.setRow(0, m0); M.setRow(1, m1); M.setRow(2, m2); return M; } }