17 #include "qgsconfig.h" 
   26 #include <gsl/gsl_linalg.h> 
   27 #include <gsl/gsl_blas.h> 
   31                               const QVector<QgsPointXY> &destinationCoordinates,
 
   32                               QgsPointXY &origin, 
double &pixelXSize, 
double &pixelYSize )
 
   34   int n = destinationCoordinates.size();
 
   37     throw std::domain_error( QObject::tr( 
"Fit to a linear transform requires at least 2 points." ).toLocal8Bit().constData() );
 
   40   double sumPx( 0 ), sumPy( 0 ), sumPx2( 0 ), sumPy2( 0 ), sumPxMx( 0 ), sumPyMy( 0 ), sumMx( 0 ), sumMy( 0 );
 
   41   for ( 
int i = 0; i < n; ++i )
 
   43     sumPx += sourceCoordinates.at( i ).x();
 
   44     sumPy += sourceCoordinates.at( i ).y();
 
   45     sumPx2 += std::pow( sourceCoordinates.at( i ).x(), 2 );
 
   46     sumPy2 += std::pow( sourceCoordinates.at( i ).y(), 2 );
 
   47     sumPxMx += sourceCoordinates.at( i ).x() * destinationCoordinates.at( i ).x();
 
   48     sumPyMy += sourceCoordinates.at( i ).y() * destinationCoordinates.at( i ).y();
 
   49     sumMx += destinationCoordinates.at( i ).x();
 
   50     sumMy += destinationCoordinates.at( i ).y();
 
   53   double deltaX = n * sumPx2 - std::pow( sumPx, 2 );
 
   54   double deltaY = n * sumPy2 - std::pow( sumPy, 2 );
 
   56   double aX = ( sumPx2 * sumMx - sumPx * sumPxMx ) / deltaX;
 
   57   double aY = ( sumPy2 * sumMy - sumPy * sumPyMy ) / deltaY;
 
   58   double bX = ( n * sumPxMx - sumPx * sumMx ) / deltaX;
 
   59   double bY = ( n * sumPyMy - sumPy * sumMy ) / deltaY;
 
   64   pixelXSize = std::fabs( bX );
 
   65   pixelYSize = std::fabs( bY );
 
   70                                const QVector<QgsPointXY> &destinationCoordinates,
 
   75   ( void )sourceCoordinates;
 
   76   ( void )destinationCoordinates;
 
   80   throw QgsNotSupportedException( QStringLiteral( 
"Calculating a helmert transformation requires a QGIS build based GSL" ) );
 
   82   int n = destinationCoordinates.size();
 
   85     throw std::domain_error( QObject::tr( 
"Fit to a Helmert transform requires at least 2 points." ).toLocal8Bit().constData() );
 
   98   for ( 
int i = 0; i < n; ++i )
 
  100     A += sourceCoordinates.at( i ).x();
 
  101     B += sourceCoordinates.at( i ).y();
 
  102     C += destinationCoordinates.at( i ).x();
 
  103     D += destinationCoordinates.at( i ).y();
 
  104     E += destinationCoordinates.at( i ).x() * sourceCoordinates.at( i ).x();
 
  105     F += destinationCoordinates.at( i ).y() * sourceCoordinates.at( i ).y();
 
  106     G += std::pow( sourceCoordinates.at( i ).x(), 2 );
 
  107     H += std::pow( sourceCoordinates.at( i ).y(), 2 );
 
  108     I += destinationCoordinates.at( i ).x() * sourceCoordinates.at( i ).y();
 
  109     J += sourceCoordinates.at( i ).x() * destinationCoordinates.at( i ).y();
 
  117   double MData[] = { A,   -B, ( double ) n,    0.,
 
  118                      B,    A,    0., ( 
double ) n,
 
  123   double bData[] = { C,    D,    E + F,  J - I };
 
  126   gsl_matrix_view M = gsl_matrix_view_array( MData, 4, 4 );
 
  127   gsl_vector_view b = gsl_vector_view_array( bData, 4 );
 
  128   gsl_vector *x = gsl_vector_alloc( 4 );
 
  129   gsl_permutation *p = gsl_permutation_alloc( 4 );
 
  131   gsl_linalg_LU_decomp( &M.matrix, p, &s );
 
  132   gsl_linalg_LU_solve( &M.matrix, p, &b.vector, x );
 
  133   gsl_permutation_free( p );
 
  135   origin.
setX( gsl_vector_get( x, 2 ) );
 
  136   origin.
setY( gsl_vector_get( x, 3 ) );
 
  137   pixelSize = std::sqrt( std::pow( gsl_vector_get( x, 0 ), 2 ) +
 
  138                          std::pow( gsl_vector_get( x, 1 ), 2 ) );
 
  139   rotation = std::atan2( gsl_vector_get( x, 1 ), gsl_vector_get( x, 0 ) );
 
  144 void QgsLeastSquares::affine( QVector<QgsPointXY> mapCoords,
 
  145                               QVector<QgsPointXY> pixelCoords )
 
  147   int n = mapCoords.size();
 
  150     throw std::domain_error( QObject::tr( 
"Fit to an affine transform requires at least 4 points." ).toLocal8Bit().constData() );
 
  153   double A = 0, B = 0, C = 0, D = 0, E = 0, F = 0,
 
  154          G = 0, H = 0, I = 0, J = 0, K = 0;
 
  155   for ( 
int i = 0; i < n; ++i )
 
  157     A += pixelCoords[i].x();
 
  158     B += pixelCoords[i].y();
 
  159     C += mapCoords[i].x();
 
  160     D += mapCoords[i].y();
 
  161     E += std::pow( pixelCoords[i].x(), 2 );
 
  162     F += std::pow( pixelCoords[i].y(), 2 );
 
  163     G += pixelCoords[i].x() * pixelCoords[i].y();
 
  164     H += pixelCoords[i].x() * mapCoords[i].x();
 
  165     I += pixelCoords[i].y() * mapCoords[i].y();
 
  166     J += pixelCoords[i].x() * mapCoords[i].y();
 
  167     K += mapCoords[i].x() * pixelCoords[i].y();
 
  175   double MData[] = { A,    B,    0,    0, ( double ) n,    0,
 
  176                      0,    0,    A,    B,    0, ( 
double ) n,
 
  183   double bData[] = { C,    D,    H,    K,    J,    I };
 
  186   gsl_matrix_view M = gsl_matrix_view_array( MData, 6, 6 );
 
  187   gsl_vector_view b = gsl_vector_view_array( bData, 6 );
 
  188   gsl_vector *x = gsl_vector_alloc( 6 );
 
  189   gsl_permutation *p = gsl_permutation_alloc( 6 );
 
  191   gsl_linalg_LU_decomp( &M.matrix, p, &s );
 
  192   gsl_linalg_LU_solve( &M.matrix, p, &b.vector, x );
 
  193   gsl_permutation_free( p );
 
  204                            double normalizeMatrix[9], 
double denormalizeMatrix[9] )
 
  207   double cogX = 0.0, cogY = 0.0;
 
  208   for ( 
int i = 0; i < coords.size(); i++ )
 
  210     cogX += coords[i].x();
 
  211     cogY += coords[i].y();
 
  213   cogX *= 1.0 / coords.size();
 
  214   cogY *= 1.0 / coords.size();
 
  217   double meanDist = 0.0;
 
  218   for ( 
int i = 0; i < coords.size(); i++ )
 
  220     double X = ( coords[i].x() - cogX );
 
  221     double Y = ( coords[i].y() - cogY );
 
  222     meanDist += std::sqrt( X * X + Y * Y );
 
  224   meanDist *= 1.0 / coords.size();
 
  226   double OOD = meanDist * M_SQRT1_2;
 
  227   double D   = 1.0 / OOD;
 
  228   normalizedCoords.resize( coords.size() );
 
  229   for ( 
int i = 0; i < coords.size(); i++ )
 
  231     normalizedCoords[i] = 
QgsPointXY( ( coords[i].x() - cogX ) * D, ( coords[i].y() - cogY ) * D );
 
  234   normalizeMatrix[0] = D;
 
  235   normalizeMatrix[1] = 0.0;
 
  236   normalizeMatrix[2] = -cogX * D;
 
  237   normalizeMatrix[3] = 0.0;
 
  238   normalizeMatrix[4] = D;
 
  239   normalizeMatrix[5] = -cogY * D;
 
  240   normalizeMatrix[6] = 0.0;
 
  241   normalizeMatrix[7] = 0.0;
 
  242   normalizeMatrix[8] = 1.0;
 
  244   denormalizeMatrix[0] = OOD;
 
  245   denormalizeMatrix[1] = 0.0;
 
  246   denormalizeMatrix[2] = cogX;
 
  247   denormalizeMatrix[3] = 0.0;
 
  248   denormalizeMatrix[4] = OOD;
 
  249   denormalizeMatrix[5] = cogY;
 
  250   denormalizeMatrix[6] = 0.0;
 
  251   denormalizeMatrix[7] = 0.0;
 
  252   denormalizeMatrix[8] = 1.0;
 
  258                                   const QVector<QgsPointXY> &destinationCoordinates,
 
  262   ( void )sourceCoordinates;
 
  263   ( void )destinationCoordinates;
 
  265   throw QgsNotSupportedException( QStringLiteral( 
"Calculating a projective transformation requires a QGIS build based GSL" ) );
 
  267   Q_ASSERT( sourceCoordinates.size() == destinationCoordinates.size() );
 
  269   if ( destinationCoordinates.size() < 4 )
 
  271     throw std::domain_error( QObject::tr( 
"Fitting a projective transform requires at least 4 corresponding points." ).toLocal8Bit().constData() );
 
  274   QVector<QgsPointXY> sourceCoordinatesNormalized;
 
  275   QVector<QgsPointXY> destinationCoordinatesNormalized;
 
  277   double normSource[9], denormSource[9];
 
  278   double normDest[9], denormDest[9];
 
  279   normalizeCoordinates( sourceCoordinates, sourceCoordinatesNormalized, normSource, denormSource );
 
  280   normalizeCoordinates( destinationCoordinates, destinationCoordinatesNormalized, normDest, denormDest );
 
  284   uint m = std::max( 9u, ( uint )destinationCoordinatesNormalized.size() * 2u );
 
  286   gsl_matrix *S = gsl_matrix_alloc( m, n );
 
  288   for ( 
int i = 0; i < destinationCoordinatesNormalized.size(); i++ )
 
  290     gsl_matrix_set( S, i * 2, 0, sourceCoordinatesNormalized[i].x() );
 
  291     gsl_matrix_set( S, i * 2, 1, sourceCoordinatesNormalized[i].y() );
 
  292     gsl_matrix_set( S, i * 2, 2, 1.0 );
 
  294     gsl_matrix_set( S, i * 2, 3, 0.0 );
 
  295     gsl_matrix_set( S, i * 2, 4, 0.0 );
 
  296     gsl_matrix_set( S, i * 2, 5, 0.0 );
 
  298     gsl_matrix_set( S, i * 2, 6, -destinationCoordinatesNormalized[i].x()*sourceCoordinatesNormalized[i].x() );
 
  299     gsl_matrix_set( S, i * 2, 7, -destinationCoordinatesNormalized[i].x()*sourceCoordinatesNormalized[i].y() );
 
  300     gsl_matrix_set( S, i * 2, 8, -destinationCoordinatesNormalized[i].x() * 1.0 );
 
  302     gsl_matrix_set( S, i * 2 + 1, 0, 0.0 );
 
  303     gsl_matrix_set( S, i * 2 + 1, 1, 0.0 );
 
  304     gsl_matrix_set( S, i * 2 + 1, 2, 0.0 );
 
  306     gsl_matrix_set( S, i * 2 + 1, 3, sourceCoordinatesNormalized[i].x() );
 
  307     gsl_matrix_set( S, i * 2 + 1, 4, sourceCoordinatesNormalized[i].y() );
 
  308     gsl_matrix_set( S, i * 2 + 1, 5, 1.0 );
 
  310     gsl_matrix_set( S, i * 2 + 1, 6, -destinationCoordinatesNormalized[i].y()*sourceCoordinatesNormalized[i].x() );
 
  311     gsl_matrix_set( S, i * 2 + 1, 7, -destinationCoordinatesNormalized[i].y()*sourceCoordinatesNormalized[i].y() );
 
  312     gsl_matrix_set( S, i * 2 + 1, 8, -destinationCoordinatesNormalized[i].y() * 1.0 );
 
  315   if ( destinationCoordinatesNormalized.size() == 4 )
 
  323     for ( 
int j = 0; j < 9; j++ )
 
  325       gsl_matrix_set( S, 8, j, gsl_matrix_get( S, 7, j ) );
 
  333   gsl_matrix *V = gsl_matrix_alloc( n, n );
 
  334   gsl_vector *singular_values = gsl_vector_alloc( n );
 
  335   gsl_vector *work = gsl_vector_alloc( n );
 
  339   gsl_linalg_SV_decomp( S, V, singular_values, work );
 
  342   for ( 
unsigned int i = 0; i < n; i++ )
 
  344     H[i] = gsl_matrix_get( V, i, n - 1 );
 
  347   gsl_matrix *prodMatrix = gsl_matrix_alloc( 3, 3 );
 
  349   gsl_matrix_view Hmatrix = gsl_matrix_view_array( H, 3, 3 );
 
  350   gsl_matrix_view normSourceMatrix = gsl_matrix_view_array( normSource, 3, 3 );
 
  351   gsl_matrix_view denormDestMatrix = gsl_matrix_view_array( denormDest, 3, 3 );
 
  355   gsl_blas_dgemm( CblasNoTrans, CblasNoTrans, 1.0, &Hmatrix.matrix, &normSourceMatrix.matrix, 0.0, prodMatrix );
 
  356   gsl_blas_dgemm( CblasNoTrans, CblasNoTrans, 1.0, &denormDestMatrix.matrix, prodMatrix, 0.0, &Hmatrix.matrix );
 
  358   gsl_matrix_free( prodMatrix );
 
  359   gsl_matrix_free( S );
 
  360   gsl_matrix_free( V );
 
  361   gsl_vector_free( singular_values );
 
  362   gsl_vector_free( work );
 
static void helmert(const QVector< QgsPointXY > &sourceCoordinates, const QVector< QgsPointXY > &destinationCoordinates, QgsPointXY &origin, double &pixelSize, double &rotation)
Transforms the point at origin in-place, using a helmert transformation calculated from the list of s...
static void projective(const QVector< QgsPointXY > &sourceCoordinates, const QVector< QgsPointXY > &destinationCoordinates, double H[9])
Calculates projective parameters from the list of source and destination Ground Control Points (GCPs)...
static void linear(const QVector< QgsPointXY > &sourceCoordinates, const QVector< QgsPointXY > &destinationCoordinates, QgsPointXY &origin, double &pixelXSize, double &pixelYSize)
Transforms the point at origin in-place, using a linear transformation calculated from the list of so...
Custom exception class which is raised when an operation is not supported.
A class to represent a 2D point.
void setX(double x) SIP_HOLDGIL
Sets the x value of the point.
void setY(double y) SIP_HOLDGIL
Sets the y value of the point.
void normalizeCoordinates(const QVector< QgsPointXY > &coords, QVector< QgsPointXY > &normalizedCoords, double normalizeMatrix[9], double denormalizeMatrix[9])
Scales the given coordinates so that the center of gravity is at the origin and the mean distance to ...