1 /***************************************************************************
2 qgsgcplistmodel.cpp - Model implementation of GCPList Model/View
3 --------------------------------------
4 Date : 27-Feb-2009
5 Copyright : (c) 2009 by Manuel Massing
6 Email : m.massing at warped-space.de
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgsgcplist.h"
17 #include "qgsgcplistmodel.h"
18 #include "qgis.h"
19 #include "qgsgeorefdatapoint.h"
20 #include "qgsgeoreftransform.h"
21 #include "qgssettings.h"
22
23 #include <cmath>
24
25 class QgsStandardItem : public QStandardItem
26 {
27 public:
QgsStandardItem(const QString & text)28 explicit QgsStandardItem( const QString &text ) : QStandardItem( text )
29 {
30 // In addition to the DisplayRole, also set the user role, which is used for sorting.
31 // This is needed for numerical sorting to work correctly (otherwise sorting is lexicographic).
32 setData( QVariant( text ), Qt::UserRole );
33 setTextAlignment( Qt::AlignRight );
34 }
35
QgsStandardItem(int value)36 explicit QgsStandardItem( int value ) : QStandardItem( QString::number( value ) )
37 {
38 setData( QVariant( value ), Qt::UserRole );
39 setTextAlignment( Qt::AlignCenter );
40 }
41
QgsStandardItem(double value)42 explicit QgsStandardItem( double value ) : QStandardItem( QString::number( value, 'f', 4 ) )
43 {
44 setData( QVariant( value ), Qt::UserRole );
45 //show the full precision when editing points
46 setData( QVariant( value ), Qt::EditRole );
47 setData( QVariant( value ), Qt::ToolTipRole );
48 setTextAlignment( Qt::AlignRight );
49 }
50 };
51
QgsGCPListModel(QObject * parent)52 QgsGCPListModel::QgsGCPListModel( QObject *parent )
53 : QStandardItemModel( parent )
54 {
55 // Use data provided by Qt::UserRole as sorting key (needed for numerical sorting).
56 setSortRole( Qt::UserRole );
57 }
58
setGCPList(QgsGCPList * theGCPList)59 void QgsGCPListModel::setGCPList( QgsGCPList *theGCPList )
60 {
61 mGCPList = theGCPList;
62 updateModel();
63 }
64
65 // ------------------------------- public ---------------------------------- //
setGeorefTransform(QgsGeorefTransform * georefTransform)66 void QgsGCPListModel::setGeorefTransform( QgsGeorefTransform *georefTransform )
67 {
68 mGeorefTransform = georefTransform;
69 updateModel();
70 }
71
updateModel()72 void QgsGCPListModel::updateModel()
73 {
74 //clear();
75 if ( !mGCPList )
76 return;
77
78 bool bTransformUpdated = false;
79
80 QVector<QgsPointXY> mapCoords, pixelCoords;
81 mGCPList->createGCPVectors( mapCoords, pixelCoords );
82
83 // // Setup table header
84 QStringList itemLabels;
85 QString unitType;
86 QgsSettings s;
87 bool mapUnitsPossible = false;
88
89 if ( mGeorefTransform )
90 {
91 bTransformUpdated = mGeorefTransform->updateParametersFromGCPs( mapCoords, pixelCoords );
92 mapUnitsPossible = mGeorefTransform->providesAccurateInverseTransformation();
93 }
94
95
96 if ( s.value( QStringLiteral( "/Plugin-GeoReferencer/Config/ResidualUnits" ) ) == "mapUnits" && mapUnitsPossible )
97 {
98 unitType = tr( "map units" );
99 }
100 else
101 {
102 unitType = tr( "pixels" );
103 }
104
105 itemLabels << tr( "Visible" )
106 << tr( "ID" )
107 << tr( "Source X" )
108 << tr( "Source Y" )
109 << tr( "Dest. X" )
110 << tr( "Dest. Y" )
111 << tr( "dX (%1)" ).arg( unitType )
112 << tr( "dY (%1)" ).arg( unitType )
113 << tr( "Residual (%1)" ).arg( unitType );
114
115 setHorizontalHeaderLabels( itemLabels );
116 setRowCount( mGCPList->size() );
117
118 for ( int i = 0; i < mGCPList->sizeAll(); ++i )
119 {
120 int j = 0;
121 QgsGeorefDataPoint *p = mGCPList->at( i );
122
123 if ( !p )
124 continue;
125
126 p->setId( i );
127
128 QStandardItem *si = new QStandardItem();
129 si->setTextAlignment( Qt::AlignCenter );
130 si->setCheckable( true );
131 if ( p->isEnabled() )
132 si->setCheckState( Qt::Checked );
133 else
134 si->setCheckState( Qt::Unchecked );
135
136 setItem( i, j++, si );
137 setItem( i, j++, new QgsStandardItem( i ) );
138 setItem( i, j++, new QgsStandardItem( p->pixelCoords().x() ) );
139 setItem( i, j++, new QgsStandardItem( p->pixelCoords().y() ) );
140 setItem( i, j++, new QgsStandardItem( p->mapCoords().x() ) );
141 setItem( i, j++, new QgsStandardItem( p->mapCoords().y() ) );
142
143 double residual;
144 double dX = 0;
145 double dY = 0;
146 // Calculate residual if transform is available and up-to-date
147 if ( mGeorefTransform && bTransformUpdated && mGeorefTransform->parametersInitialized() )
148 {
149 QgsPointXY dst;
150 QgsPointXY pixel = mGeorefTransform->hasCrs() ? mGeorefTransform->toColumnLine( p->pixelCoords() ) : p->pixelCoords();
151 if ( unitType == tr( "pixels" ) )
152 {
153 // Transform from world to raster coordinate:
154 // This is the transform direction used by the warp operation.
155 // As transforms of order >=2 are not invertible, we are only
156 // interested in the residual in this direction
157 if ( mGeorefTransform->transformWorldToRaster( p->mapCoords(), dst ) )
158 {
159 dX = ( dst.x() - pixel.x() );
160 dY = -( dst.y() - pixel.y() );
161 }
162 }
163 else if ( unitType == tr( "map units" ) )
164 {
165 if ( mGeorefTransform->transformRasterToWorld( pixel, dst ) )
166 {
167 dX = ( dst.x() - p->mapCoords().x() );
168 dY = ( dst.y() - p->mapCoords().y() );
169 }
170 }
171 }
172 residual = std::sqrt( dX * dX + dY * dY );
173
174 p->setResidual( QPointF( dX, dY ) );
175
176 if ( residual >= 0.f )
177 {
178 setItem( i, j++, new QgsStandardItem( dX ) );
179 setItem( i, j++, new QgsStandardItem( dY ) );
180 setItem( i, j++, new QgsStandardItem( residual ) );
181 }
182 else
183 {
184 setItem( i, j++, new QgsStandardItem( QStringLiteral( "n/a" ) ) );
185 setItem( i, j++, new QgsStandardItem( QStringLiteral( "n/a" ) ) );
186 setItem( i, j++, new QgsStandardItem( QStringLiteral( "n/a" ) ) );
187 }
188 }
189 }
190
191 // --------------------------- public slots -------------------------------- //
replaceDataPoint(QgsGeorefDataPoint * newDataPoint,int i)192 void QgsGCPListModel::replaceDataPoint( QgsGeorefDataPoint *newDataPoint, int i )
193 {
194 mGCPList->replace( i, newDataPoint );
195 }
196
onGCPListModified()197 void QgsGCPListModel::onGCPListModified()
198 {
199 }
200
onTransformationModified()201 void QgsGCPListModel::onTransformationModified()
202 {
203 }
204