Index: src/plugins/georeferencer/qgsgcpcanvasitem.cpp =================================================================== --- src/plugins/georeferencer/qgsgcpcanvasitem.cpp (revision 13350) +++ src/plugins/georeferencer/qgsgcpcanvasitem.cpp (working copy) @@ -35,6 +35,12 @@ void QgsGCPCanvasItem::paint( QPainter* p ) { + QgsRenderContext context; + if ( !setRenderContextVariables( p, context ) ) + { + return; + } + p->setRenderHint( QPainter::Antialiasing ); bool enabled = true; @@ -57,29 +63,39 @@ QSettings s; bool showIDs = s.value( "/Plugin-GeoReferencer/Config/ShowId" ).toBool(); - if ( !showIDs && mIsGCPSource ) + bool showCoords = s.value( "/Plugin-GeoReferencer/Config/ShowCoords" ).toBool(); + + QString msg; + if ( showIDs && showCoords ) { - QString msg = QString( "X %1\nY %2" ).arg( QString::number( worldCoords.x(), 'f' ) ). - arg( QString::number( worldCoords.y(), 'f' ) ); - p->setFont( QFont( "helvetica", 9 ) ); - QRect textBounds = p->boundingRect( 6, 6, 10, 10, Qt::AlignLeft, msg ); - p->setBrush( mLabelBrush ); - p->drawRect( textBounds.x() - 2, textBounds.y() - 2, textBounds.width() + 4, textBounds.height() + 4 ); - p->drawText( textBounds, Qt::AlignLeft, msg ); - mTextBounds = QSizeF( textBounds.width() + 4, textBounds.height() + 4 ); + msg = QString( "%1\nX %2\nY %3" ).arg( QString::number( id ) ).arg( QString::number( worldCoords.x(), 'f' ) ).arg( QString::number( worldCoords.y(), 'f' ) ); } else if ( showIDs ) { - p->setFont( QFont( "helvetica", 12 ) ); - QString msg = QString::number( id ); + msg = msg = QString::number( id ); + } + else if ( showCoords ) + { + msg = QString( "X %1\nY %2" ).arg( QString::number( worldCoords.x(), 'f' ) ).arg( QString::number( worldCoords.y(), 'f' ) ); + } + + if ( !msg.isEmpty() ) + { p->setBrush( mLabelBrush ); - p->drawRect( 5, 4, p->fontMetrics().width( msg ) + 2, 14 ); - p->drawText( 6, 16, msg ); - QFontMetrics fm = p->fontMetrics(); - mTextBounds = QSize( fm.width( msg ) + 4, fm.height() + 4 ); + QFont textFont( "helvetica" ); + textFont.setPixelSize( fontSizePainterUnits( 12, context ) ); + p->setFont( textFont ); + QRectF textBounds = p->boundingRect( 3 * context.scaleFactor(), 3 * context.scaleFactor(), 5 * context.scaleFactor(), 5 * context.scaleFactor(), Qt::AlignLeft, msg ); + mTextBoxRect = QRectF( textBounds.x() - context.scaleFactor() * 1, textBounds.y() - context.scaleFactor() * 1, \ + textBounds.width() + 2 * context.scaleFactor(), textBounds.height() + 2 * context.scaleFactor() ); + p->drawRect( mTextBoxRect ); + p->drawText( textBounds, Qt::AlignLeft, msg ); } - drawResidualArrow( p ); + if ( data( 0 ) != "composer" ) //draw residuals only on screen + { + drawResidualArrow( p, context ); + } } QRectF QgsGCPCanvasItem::boundingRect() const @@ -91,6 +107,8 @@ { residual = mDataPoint->residual(); } + + //only considering screen resolution is ok for the bounding box function double rf = residualToScreenFactor(); if ( residual.x() > 0 ) @@ -116,7 +134,12 @@ QRectF residualArrowRect( QPointF( residualLeft, residualTop ), QPointF( residualRight, residualBottom ) ); QRectF markerRect( -2, -2, mTextBounds.width() + 6, mTextBounds.height() + 6 ); - return residualArrowRect.united( markerRect ); + QRectF boundingRect = residualArrowRect.united( markerRect ); + if ( !mTextBoxRect.isNull() ) + { + boundingRect = boundingRect.united( mTextBoxRect ); + } + return boundingRect; } QPainterPath QgsGCPCanvasItem::shape() const @@ -138,9 +161,9 @@ setPos( toCanvasCoordinates( mIsGCPSource ? mDataPoint->pixelCoords() : mDataPoint->mapCoords() ) ); } -void QgsGCPCanvasItem::drawResidualArrow( QPainter* p ) +void QgsGCPCanvasItem::drawResidualArrow( QPainter* p, const QgsRenderContext& context ) { - if ( !mDataPoint || !mIsGCPSource ) + if ( !mDataPoint || !mIsGCPSource || !mMapCanvas ) { return; } @@ -188,3 +211,9 @@ { prepareGeometryChange(); } + +double QgsGCPCanvasItem::fontSizePainterUnits( double points, const QgsRenderContext& c ) +{ + return points * 0.3527 * c.scaleFactor(); +} + Index: src/plugins/georeferencer/qgsresidualplotitem.cpp =================================================================== --- src/plugins/georeferencer/qgsresidualplotitem.cpp (revision 0) +++ src/plugins/georeferencer/qgsresidualplotitem.cpp (revision 0) @@ -0,0 +1,207 @@ +#include "qgsresidualplotitem.h" +#include "qgsgeorefdatapoint.h" +#include +#include +#ifndef Q_OS_MACX +#include +#else +#include +#endif + +QgsResidualPlotItem::QgsResidualPlotItem( QgsComposition* c ): QgsComposerItem( c ), mConvertScaleToMapUnits( false ), mPixelToMapUnits( 1.0 ) +{ + +} + +QgsResidualPlotItem::~QgsResidualPlotItem() +{ + +} + +void QgsResidualPlotItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget ) +{ + if ( mGCPList.size() < 1 || !painter ) + { + return; + } + + double widthMM = rect().width(); + double heightMM = rect().height(); + + QPen enabledPen( QColor( 0, 0, 255, 255 ) ); + enabledPen.setWidthF( 0.4 ); + QPen disabledPen( QColor( 0, 0, 255, 127 ) ); + disabledPen.setWidthF( 0.3 ); + QBrush enabledBrush( QColor( 255, 0, 0, 255 ) ); + QBrush disabledBrush( QColor( 255, 0, 0, 127 ) ); + + //draw all points and collect minimal mm/pixel ratio + double minMMPixelRatio = DBL_MAX; + double mmPixelRatio = 1; + + painter->setRenderHint( QPainter::Antialiasing, true ); + + QgsGCPList::const_iterator gcpIt = mGCPList.constBegin(); + for ( ; gcpIt != mGCPList.constEnd(); ++gcpIt ) + { + QgsPoint gcpCoords = ( *gcpIt )->pixelCoords(); + double gcpItemMMX = ( gcpCoords.x() - mExtent.xMinimum() ) / mExtent.width() * widthMM; + double gcpItemMMY = ( 1 - ( gcpCoords.y() - mExtent.yMinimum() ) / mExtent.height() ) * heightMM; + + if (( *gcpIt )->isEnabled() ) + { + painter->setPen( enabledPen ); + painter->setBrush( enabledBrush ); + } + else + { + painter->setPen( disabledPen ); + painter->setBrush( disabledBrush ); + } + painter->drawRect( QRectF( gcpItemMMX - 1, gcpItemMMY - 1, 2, 2 ) ); + drawText( painter, gcpItemMMX + 2, gcpItemMMY + 2, QString::number(( *gcpIt )->id() ), QFont() ); + + mmPixelRatio = maxMMToPixelRatioForGCP( *gcpIt, gcpItemMMX, gcpItemMMY ); + if ( mmPixelRatio < minMMPixelRatio ) + { + minMMPixelRatio = mmPixelRatio; + } + } + + //draw residual arrows + gcpIt = mGCPList.constBegin(); + for ( ; gcpIt != mGCPList.constEnd(); ++gcpIt ) + { + QgsPoint gcpCoords = ( *gcpIt )->pixelCoords(); + double gcpItemMMX = ( gcpCoords.x() - mExtent.xMinimum() ) / mExtent.width() * widthMM; + double gcpItemMMY = ( 1 - ( gcpCoords.y() - mExtent.yMinimum() ) / mExtent.height() ) * heightMM; + if (( *gcpIt )->isEnabled() ) + { + painter->setPen( enabledPen ); + } + else + { + painter->setPen( disabledPen ); + } + + QPointF p1( gcpItemMMX, gcpItemMMY ); + QPointF p2( gcpItemMMX + ( *gcpIt )->residual().x() * minMMPixelRatio, gcpItemMMY + ( *gcpIt )->residual().y() * minMMPixelRatio ); + painter->drawLine( p1, p2 ); + painter->setBrush( QBrush( painter->pen().color() ) ); + drawArrowHead( painter, p2.x(), p2.y(), angle( p1, p2 ), 1 ); + } + + //draw scale bar + double initialScaleBarWidth = rect().width() / 5; + int nUnits; + double scaleBarWidth; + if ( mConvertScaleToMapUnits ) //map units + { + nUnits = initialScaleBarWidth / minMMPixelRatio * mPixelToMapUnits; + scaleBarWidth = nUnits * minMMPixelRatio / mPixelToMapUnits; + } + else //pixels + { + nUnits = initialScaleBarWidth / minMMPixelRatio; + scaleBarWidth = nUnits * minMMPixelRatio; + } + + painter->setPen( QColor( 0, 0, 0 ) ); + painter->drawLine( QPointF( 5, rect().height() - 5 ), QPointF( 5 + scaleBarWidth, rect().height() - 5 ) ); + painter->drawLine( QPointF( 5, rect().height() - 5 ), QPointF( 5, rect().height() - 7 ) ); + painter->drawLine( QPointF( 5 + scaleBarWidth, rect().height() - 5 ), QPointF( 5 + scaleBarWidth, rect().height() - 7 ) ); + QFont scaleBarFont; + if ( mConvertScaleToMapUnits ) + { + drawText( painter, 5, rect().height() - 4 + fontAscentMillimeters( scaleBarFont ), QString( "%1 map units" ).arg( nUnits ), QFont() ); + } + else + { + drawText( painter, 5, rect().height() - 4 + fontAscentMillimeters( scaleBarFont ), QString( "%1 pixels" ).arg( nUnits ), QFont() ); + } + + drawFrame( painter ); + if ( isSelected() ) + { + drawSelectionBoxes( painter ); + } +} + +double QgsResidualPlotItem::maxMMToPixelRatioForGCP( const QgsGeorefDataPoint* p, double pixelXMM, double pixelYMM ) +{ + if ( !p ) + { + return 0; + } + + //calculate intersections with upper / lower frame edge depending on the residual y sign + double upDownDist = DBL_MAX; //distance to frame intersection with lower or upper frame + double leftRightDist = DBL_MAX; //distance to frame intersection with left or right frame + + QPointF residual = p->residual(); + QLineF residualLine( pixelXMM, pixelYMM, pixelXMM + residual.x(), pixelYMM + residual.y() ); + QPointF intersectionPoint; + double dx, dy; + + if ( residual.y() > 0 ) + { + QLineF lowerFrameLine( 0, rect().height(), rect().width(), rect().height() ); + if ( residualLine.intersect( lowerFrameLine, &intersectionPoint ) != QLineF::NoIntersection ) + { + upDownDist = dist( QPointF( pixelXMM, pixelYMM ) , intersectionPoint ); + } + } + else if ( residual.y() < 0 ) + { + QLineF upperFrameLine( 0, 0, mExtent.xMaximum(), 0 ); + if ( residualLine.intersect( upperFrameLine, &intersectionPoint ) != QLineF::NoIntersection ) + { + upDownDist = dist( QPointF( pixelXMM, pixelYMM ) , intersectionPoint ); + } + } + + //calculate intersection with left / right frame edge depending on the residual x sign + if ( residual.x() > 0 ) + { + QLineF rightFrameLine( rect().width(), 0, rect().width(), rect().height() ); + if ( residualLine.intersect( rightFrameLine, &intersectionPoint ) != QLineF::NoIntersection ) + { + leftRightDist = dist( QPointF( pixelXMM, pixelYMM ) , intersectionPoint ); + } + } + else if ( residual.x() < 0 ) + { + QLineF leftFrameLine( 0, 0 , 0, rect().height() ); + if ( residualLine.intersect( leftFrameLine, &intersectionPoint ) != QLineF::NoIntersection ) + { + leftRightDist = dist( QPointF( pixelXMM, pixelYMM ) , intersectionPoint ); + } + } + + double resTot = sqrt( residual.x() * residual.x() + residual.y() * residual.y() ); + if ( leftRightDist <= upDownDist ) + { + return leftRightDist / resTot; + } + else + { + return upDownDist / resTot; + } +} + +bool QgsResidualPlotItem::writeXML( QDomElement& elem, QDomDocument & doc ) const +{ + return false; +} + +bool QgsResidualPlotItem::readXML( const QDomElement& itemElem, const QDomDocument& doc ) +{ + return false; +} + +double QgsResidualPlotItem::dist( const QPointF& p1, const QPointF& p2 ) const +{ + double dx = p2.x() - p1.x(); + double dy = p2.y() - p1.y(); + return sqrt( dx * dx + dy * dy ); +} Index: src/plugins/georeferencer/qgsgeorefplugingui.h =================================================================== --- src/plugins/georeferencer/qgsgeorefplugingui.h (revision 13350) +++ src/plugins/georeferencer/qgsgeorefplugingui.h (working copy) @@ -131,13 +131,14 @@ // georeference bool georeference(); - bool writeWorldFile( QgsPoint origin, double pixelXSize, double pixelYSize ); + bool writeWorldFile( QgsPoint origin, double pixelXSize, double pixelYSize, double rotation ); + bool writePDFReportFile( const QString& fileName, const QgsGeorefTransform& transform ); // gdal script void showGDALScript( int argNum... ); - QString generateGDALtranslateCommand( bool generateTFW = true); + QString generateGDALtranslateCommand( bool generateTFW = true ); /* Generate command-line for gdalwarp based on current GCPs and given parameters. - * For values in the range 1 to 3, the parameter "order" prescribes the degree of the interpolating polynomials to use, + * For values in the range 1 to 3, the parameter "order" prescribes the degree of the interpolating polynomials to use, * a value of -1 indicates that thin plate spline interpolation should be used for warping.*/ QString generateGDALwarpCommand( QString resampling, QString compress, bool useZeroForTrans, int order, double targetResX, double targetResY ); @@ -158,7 +159,10 @@ void logRequaredGCPs(); void clearGCPData(); + /**Docks / undocks this window*/ + void dockThisWindow( bool dock ); + QMenu *mPanelMenu; QMenu *mToolbarMenu; @@ -177,6 +181,7 @@ QString mTranslatedRasterFileName; QString mGCPpointsFileName; QString mProjection; + QString mPdfOutputFile; double mUserResX, mUserResY; // User specified target scale QgsGeorefTransform::TransformParametrisation mTransformParam; @@ -205,5 +210,7 @@ bool mExtentsChangedRecursionGuard; bool mGCPsDirty; bool mLoadInQgis; + + QDockWidget* mDock; }; #endif Index: src/plugins/georeferencer/qgsgeorefconfigdialogbase.ui =================================================================== --- src/plugins/georeferencer/qgsgeorefconfigdialogbase.ui (revision 13350) +++ src/plugins/georeferencer/qgsgeorefconfigdialogbase.ui (working copy) @@ -6,32 +6,29 @@ 0 0 - 221 - 102 + 219 + 162 Configure Georeferencer - + Point tip - - - + + + Show IDs - - true - - - + + Show coords @@ -41,6 +38,13 @@ + + + Show Georeferencer window docked + + + + Qt::Horizontal Index: src/plugins/georeferencer/qgsgeoreftransform.h =================================================================== --- src/plugins/georeferencer/qgsgeoreftransform.h (revision 13350) +++ src/plugins/georeferencer/qgsgeoreftransform.h (working copy) @@ -129,6 +129,10 @@ //! \brief Returns origin and scale if this is a linear transform, fails otherwise. bool getLinearOriginScale( QgsPoint &origin, double &scaleX, double &scaleY ) const; + + //! \brief Returns origin, scale and rotation for linear and helmert transform, fails otherwise. + bool getOriginRotationScale( QgsPoint &origin, double &scaleX, double &scaleY, double& rotation ) const; + private: // shallow copy constructor QgsGeorefTransform( const QgsGeorefTransform &other ); Index: src/plugins/georeferencer/qgstransformsettingsdialog.cpp =================================================================== --- src/plugins/georeferencer/qgstransformsettingsdialog.cpp (revision 13350) +++ src/plugins/georeferencer/qgstransformsettingsdialog.cpp (working copy) @@ -34,13 +34,13 @@ { setupUi( this ); - cmbTransformType->addItem( tr( "Linear" ) , (int)QgsGeorefTransform::Linear ) ; - cmbTransformType->addItem( tr( "Helmert" ), (int)QgsGeorefTransform::Helmert ); - cmbTransformType->addItem( tr( "Polynomial 1" ), (int)QgsGeorefTransform::PolynomialOrder1 ); - cmbTransformType->addItem( tr( "Polynomial 2" ), (int)QgsGeorefTransform::PolynomialOrder2 ); - cmbTransformType->addItem( tr( "Polynomial 3" ), (int)QgsGeorefTransform::PolynomialOrder3 ); - cmbTransformType->addItem( tr( "Thin Plate Spline" ), (int)QgsGeorefTransform::ThinPlateSpline ); - + cmbTransformType->addItem( tr( "Linear" ) , ( int )QgsGeorefTransform::Linear ) ; + cmbTransformType->addItem( tr( "Helmert" ), ( int )QgsGeorefTransform::Helmert ); + cmbTransformType->addItem( tr( "Polynomial 1" ), ( int )QgsGeorefTransform::PolynomialOrder1 ); + cmbTransformType->addItem( tr( "Polynomial 2" ), ( int )QgsGeorefTransform::PolynomialOrder2 ); + cmbTransformType->addItem( tr( "Polynomial 3" ), ( int )QgsGeorefTransform::PolynomialOrder3 ); + cmbTransformType->addItem( tr( "Thin Plate Spline" ), ( int )QgsGeorefTransform::ThinPlateSpline ); + leOutputRaster->setText( output ); mRegExpValidator = new QRegExpValidator( QRegExp( "(^epsg:{1}\\s*\\d+)|(^\\+proj.*)", Qt::CaseInsensitive ), leTargetSRS ); @@ -70,12 +70,13 @@ tbnOutputRaster->setIcon( getThemeIcon( "/mPushButtonFileOpen.png" ) ); tbnTargetSRS->setIcon( getThemeIcon( "/mPushButtonTargetSRSDisabled.png" ) ); + tbnReportFile->setIcon( getThemeIcon( "/mActionSaveAsPDF.png" ) ); } void QgsTransformSettingsDialog::getTransformSettings( QgsGeorefTransform::TransformParametrisation &tp, QgsImageWarper::ResamplingMethod &rm, QString &comprMethod, QString &raster, - QString &proj, bool &zt, bool &loadInQgis, + QString &proj, QString& pdfReportFile, bool &zt, bool &loadInQgis, double& resX, double& resY ) { if ( cmbTransformType->currentIndex() == -1 ) @@ -87,6 +88,7 @@ comprMethod = cmbCompressionComboBox->currentText(); raster = leOutputRaster->text(); proj = leTargetSRS->text(); + pdfReportFile = mReportFileLineEdit->text(); zt = cbxZeroAsTrans->isChecked(); loadInQgis = cbxLoadInQgisWhenDone->isChecked(); resX = 0.0; @@ -130,7 +132,7 @@ int minGCPpoints; if ( checkGCPpoints( cmbTransformType->currentIndex(), minGCPpoints ) ) { - if ( leOutputRaster->text().isEmpty() && cmbTransformType->currentIndex() != 0 ) + if ( leOutputRaster->text().isEmpty() && cmbTransformType->currentIndex() > 1 ) { QMessageBox::information( this, tr( "Info" ), tr( "Please set output name" ) ); return; @@ -156,6 +158,12 @@ s.setValue( "/Plugin-GeoReferencer/user_specified_resolution", cbxUserResolution->isChecked() ); s.setValue( "/Plugin-GeoReferencer/user_specified_resx", dsbHorizRes->value() ); s.setValue( "/Plugin-GeoReferencer/user_specified_resy", dsbVerticalRes->value() ); + QString pdfReportFileName = mReportFileLineEdit->text(); + if ( !pdfReportFileName.isEmpty() ) + { + QFileInfo fi( pdfReportFileName ); + s.setValue( "/Plugin-GeoReferencer/lastPDFReportDir", fi.absolutePath() ); + } } void QgsTransformSettingsDialog::on_tbnOutputRaster_clicked() @@ -201,6 +209,17 @@ } } +void QgsTransformSettingsDialog::on_tbnReportFile_clicked() +{ + QSettings s; + QString myLastUsedDir = s.value( "/Plugin-GeoReferencer/lastPDFReportDir", "" ).toString(); + QString outputFileName = QFileDialog::getSaveFileName( 0, tr( "Select save PDF file" ), myLastUsedDir, tr( "PDF Format" ) + " (*.pdf *PDF)" ); + if ( !outputFileName.isNull() ) + { + mReportFileLineEdit->setText( outputFileName ); + } +} + void QgsTransformSettingsDialog::on_leTargetSRS_textChanged( const QString &text ) { QString t = text; Index: src/plugins/georeferencer/qgsgeorefconfigdialog.cpp =================================================================== --- src/plugins/georeferencer/qgsgeorefconfigdialog.cpp (revision 13350) +++ src/plugins/georeferencer/qgsgeorefconfigdialog.cpp (working copy) @@ -54,13 +54,37 @@ { QSettings s; if ( s.value( "/Plugin-GeoReferencer/Config/ShowId" ).toBool() ) - mShowIDsRadioButton->setChecked( true ); + { + mShowIDsCheckBox->setChecked( true ); + } else - mShowCoordsRadioButton->setChecked( true ); + { + mShowIDsCheckBox->setChecked( false ); + } + + if ( s.value( "/Plugin-GeoReferencer/Config/ShowCoords" ).toBool() ) + { + mShowCoordsCheckBox->setChecked( true ); + } + else + { + mShowCoordsCheckBox->setChecked( false ); + } + + if ( s.value( "/Plugin-GeoReferencer/Config/ShowDocked" ).toBool() ) + { + mShowDockedCheckBox->setChecked( true ); + } + else + { + mShowDockedCheckBox->setChecked( false ); + } } void QgsGeorefConfigDialog::writeSettings() { QSettings s; - s.setValue( "/Plugin-GeoReferencer/Config/ShowId", mShowIDsRadioButton->isChecked() ); + s.setValue( "/Plugin-GeoReferencer/Config/ShowId", mShowIDsCheckBox->isChecked() ); + s.setValue( "/Plugin-GeoReferencer/Config/ShowCoords", mShowCoordsCheckBox->isChecked() ); + s.setValue( "/Plugin-GeoReferencer/Config/ShowDocked", mShowDockedCheckBox->isChecked() ); } Index: src/plugins/georeferencer/qgsgeorefdatapoint.h =================================================================== --- src/plugins/georeferencer/qgsgeorefdatapoint.h (revision 13350) +++ src/plugins/georeferencer/qgsgeorefdatapoint.h (working copy) @@ -13,6 +13,10 @@ * * ***************************************************************************/ /* $Id$ */ + +#ifndef QGSGEOREFDATAPOINT_H +#define QGSGEOREFDATAPOINT_H + #include "qgsmapcanvasitem.h" class QgsGCPCanvasItem; @@ -66,3 +70,5 @@ bool mEnabled; QPointF mResidual; }; + +#endif //QGSGEOREFDATAPOINT_H Index: src/plugins/georeferencer/CMakeLists.txt =================================================================== --- src/plugins/georeferencer/CMakeLists.txt (revision 13350) +++ src/plugins/georeferencer/CMakeLists.txt (working copy) @@ -15,6 +15,7 @@ qgsgeorefvalidators.cpp qgsleastsquares.cpp qgsmapcoordsdialog.cpp + qgsresidualplotitem.cpp qgstransformsettingsdialog.cpp qgsgcplist.cpp @@ -67,7 +68,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ../../core ../../core/raster ../../core/renderer ../../core/symbology + ../../core ../../core/raster ../../core/renderer ../../core/symbology ../../core/composer ../../gui .. ${GSL_INCLUDE_DIR} Index: src/plugins/georeferencer/qgsgcpcanvasitem.h =================================================================== --- src/plugins/georeferencer/qgsgcpcanvasitem.h (revision 13350) +++ src/plugins/georeferencer/qgsgcpcanvasitem.h (working copy) @@ -49,9 +49,14 @@ bool mIsGCPSource; QPen mResidualPen; - void drawResidualArrow( QPainter* p ); + //text box rect for bounding rect calculation (updated in the paint event) + QRectF mTextBoxRect; + + void drawResidualArrow( QPainter* p, const QgsRenderContext& context ); /**Calculates scale factor for residual display*/ double residualToScreenFactor() const; + /**Calculates pixel size for a font point size*/ + double fontSizePainterUnits( double points, const QgsRenderContext& c ); }; #endif // QGSGCPCANVASITEM_H Index: src/plugins/georeferencer/qgsgeorefplugingui.cpp =================================================================== --- src/plugins/georeferencer/qgsgeorefplugingui.cpp (revision 13350) +++ src/plugins/georeferencer/qgsgeorefplugingui.cpp (working copy) @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -32,9 +33,13 @@ #include "qgslegendinterface.h" #include "qgsapplication.h" +#include "qgscomposerlabel.h" +#include "qgscomposermap.h" +#include "qgscomposertexttable.h" #include "qgsmapcanvas.h" #include "qgsmapcoordsdialog.h" #include "qgsmaplayerregistry.h" +#include "qgsmaprenderer.h" #include "qgsmaptoolzoom.h" #include "qgsmaptoolpan.h" @@ -52,10 +57,26 @@ #include "qgsgeorefconfigdialog.h" #include "qgsgeorefdescriptiondialog.h" +#include "qgsresidualplotitem.h" #include "qgstransformsettingsdialog.h" #include "qgsgeorefplugingui.h" +class QgsGeorefDockWidget : public QDockWidget +{ + public: + QgsGeorefDockWidget( const QString & title, QWidget * parent = 0, Qt::WindowFlags flags = 0 ) + : QDockWidget( title, parent, flags ) + { + setObjectName( "GeorefDockWidget" ); // set object name so the position can be saved + } + + virtual void closeEvent( QCloseEvent * ev ) + { + deleteLater(); + } +}; + QgsGeorefPluginGui::QgsGeorefPluginGui( QgisInterface* theQgisInterface, QWidget* parent, Qt::WFlags fl ) : QMainWindow( parent, fl ) , mTransformParam( QgsGeorefTransform::InvalidTransform ) @@ -65,6 +86,7 @@ , mMapCoordsDialog( 0 ) , mUseZeroForTrans( false ) , mLoadInQgis( false ) + , mDock( 0 ) { setupUi( this ); @@ -83,8 +105,35 @@ mActionLinkQGisToGeoref->setEnabled( false ); mCanvas->clearExtentHistory(); // reset zoomnext/zoomlast + + QSettings s; + if ( s.value( "/Plugin-GeoReferencer/Config/ShowDocked" ).toBool() ) + { + dockThisWindow( true ); + } } +void QgsGeorefPluginGui::dockThisWindow( bool dock ) +{ + if ( mDock ) + { + setParent( 0 ); + show(); + mIface->removeDockWidget( mDock ); + mDock->setWidget( 0 ); + delete mDock; + mDock = 0; + } + + if ( dock ) + { + mDock = new QgsGeorefDockWidget( tr( "Georeferencer" ), mIface->mainWindow() ); + mDock->setWidget( this ); + connect( this, SIGNAL( destroyed() ), mDock, SLOT( close() ) ); + mIface->addDockWidget( Qt::BottomDockWidgetArea, mDock ); + } +} + QgsGeorefPluginGui::~QgsGeorefPluginGui() { QgsTransformSettingsDialog::resetSettings(); @@ -102,6 +151,7 @@ delete mToolAddPoint; delete mToolDeletePoint; delete mToolMovePoint; + delete mDock; } // ----------------------------- protected --------------------------------- // @@ -232,7 +282,7 @@ { if ( mLoadInQgis ) { - if ( QgsGeorefTransform::Linear == mTransformParam ) + if ( mModifiedRasterFileName.isEmpty() ) { mIface->addRasterLayer( mRasterFileName ); } @@ -264,7 +314,7 @@ } d.getTransformSettings( mTransformParam, mResamplingMethod, mCompressionMethod, - mModifiedRasterFileName, mProjection, mUseZeroForTrans, mLoadInQgis, mUserResX, mUserResY ); + mModifiedRasterFileName, mProjection, mPdfOutputFile, mUseZeroForTrans, mLoadInQgis, mUserResX, mUserResY ); mTransformParamLabel->setText( tr( "Transform: " ) + convertTransformEnumToString( mTransformParam ) ); mGeorefTransform.selectTransformParametrisation( mTransformParam ); mGCPListWidget->setGeorefTransform( &mGeorefTransform ); @@ -294,7 +344,7 @@ if ( !checkReadyGeoref() ) return; - switch (mTransformParam) + switch ( mTransformParam ) { case QgsGeorefTransform::PolynomialOrder1: case QgsGeorefTransform::PolynomialOrder2: @@ -309,10 +359,10 @@ QString resamplingStr = convertResamplingEnumToString( mResamplingMethod ); int order = polynomialOrder( mTransformParam ); - if (order != 0) + if ( order != 0 ) { gdalwarpCommand = generateGDALwarpCommand( resamplingStr, mCompressionMethod, mUseZeroForTrans, order, - mUserResX, mUserResY ); + mUserResX, mUserResY ); showGDALScript( 2, translateCommand.toAscii().data(), gdalwarpCommand.toAscii().data() ); break; } @@ -543,9 +593,22 @@ void QgsGeorefPluginGui::showGeorefConfigDialog() { QgsGeorefConfigDialog config; - config.exec(); - mCanvas->refresh(); - mIface->mapCanvas()->refresh(); + if ( config.exec() == QDialog::Accepted ) + { + mCanvas->refresh(); + mIface->mapCanvas()->refresh(); + QSettings s; + //update dock state + bool dock = s.value( "/Plugin-GeoReferencer/Config/ShowDocked" ).toBool(); + if ( dock && !mDock ) + { + dockThisWindow( true ); + } + else if ( !dock && mDock ) + { + dockThisWindow( false ); + } + } } // Info slots @@ -1042,11 +1105,12 @@ if ( !checkReadyGeoref() ) return false; - if ( QgsGeorefTransform::Linear == mGeorefTransform.transformParametrisation() ) + if ( mModifiedRasterFileName.isEmpty() && ( QgsGeorefTransform::Linear == mGeorefTransform.transformParametrisation() || \ + QgsGeorefTransform::Helmert == mGeorefTransform.transformParametrisation() ) ) { QgsPoint origin; - double pixelXSize, pixelYSize; - if ( !mGeorefTransform.getLinearOriginScale( origin, pixelXSize, pixelYSize ) ) + double pixelXSize, pixelYSize, rotation; + if ( !mGeorefTransform.getOriginRotationScale( origin, pixelXSize, pixelYSize, rotation ) ) { QMessageBox::information( this, tr( "Info" ), tr( "Failed to get linear transform parameters" ) ); @@ -1076,7 +1140,11 @@ return false; } - return writeWorldFile( origin, pixelXSize, pixelYSize ); + bool success = writeWorldFile( origin, pixelXSize, pixelYSize, rotation ); + if ( success && !mPdfOutputFile.isEmpty() ) + { + writePDFReportFile( mPdfOutputFile, mGeorefTransform ); + } } else // Helmert, Polinom 1, Polinom 2, Polinom 3 { @@ -1097,12 +1165,16 @@ } else // 1 all right { + if ( !mPdfOutputFile.isEmpty() ) + { + writePDFReportFile( mPdfOutputFile, mGeorefTransform ); + } return true; } } } -bool QgsGeorefPluginGui::writeWorldFile( QgsPoint origin, double pixelXSize, double pixelYSize ) +bool QgsGeorefPluginGui::writeWorldFile( QgsPoint origin, double pixelXSize, double pixelYSize, double rotation ) { // write the world file QFile file( mWorldFileName ); @@ -1112,16 +1184,233 @@ tr( "Could not write to %1" ).arg( mWorldFileName ) ); return false; } + + double rotationX = 0; + double rotationY = 0; + + if ( !doubleNear( rotation, 0.0 ) ) + { + rotationX = pixelXSize * sin( rotation ); + rotationY = pixelYSize * sin( rotation ); + pixelXSize *= cos( rotation ); + pixelYSize *= cos( rotation ); + } + QTextStream stream( &file ); stream << QString::number( pixelXSize, 'f', 15 ) << endl - << 0 << endl - << 0 << endl + << rotationX << endl + << rotationY << endl << QString::number( -pixelYSize, 'f', 15 ) << endl << QString::number( origin.x(), 'f', 15 ) << endl << QString::number( origin.y(), 'f', 15 ) << endl; return true; } +bool QgsGeorefPluginGui::writePDFReportFile( const QString& fileName, const QgsGeorefTransform& transform ) +{ + if ( !mCanvas ) + { + return false; + } + + QgsMapRenderer* canvasRenderer = mCanvas->mapRenderer(); + if ( !canvasRenderer ) + { + return false; + } + + QPrinter printer; + printer.setOutputFormat( QPrinter::PdfFormat ); + printer.setOutputFileName( fileName ); + + //create composition A4 with 300 dpi + QgsComposition* composition = new QgsComposition( mCanvas->mapRenderer() ); + composition->setPaperSize( 210, 297 ); //A4 + composition->setPrintResolution( 300 ); + printer.setPaperSize( QSizeF( composition->paperWidth(), composition->paperHeight() ), QPrinter::Millimeter ); + + //title + QFileInfo rasterFi( mRasterFileName ); + QgsComposerLabel* titleLabel = new QgsComposerLabel( composition ); + titleLabel->setText( rasterFi.fileName() ); + composition->addItem( titleLabel ); + titleLabel->setSceneRect( QRectF( 10, 5, composition->paperWidth(), 8 ) ); + titleLabel->setFrame( false ); + + //composer map + QgsComposerMap* composerMap = new QgsComposerMap( composition, 10, titleLabel->rect().bottom() + titleLabel->transform().dy(), 190, 277 ); + composerMap->setLayerSet( canvasRenderer->layerSet() ); + composerMap->setNewExtent( mCanvas->extent() ); + composerMap->setMapCanvas( mCanvas ); + composition->addItem( composerMap ); + printer.setFullPage( true ); + printer.setColorMode( QPrinter::Color ); + + QgsComposerTextTable* parameterTable = 0; + double scaleX, scaleY, rotation; + QgsPoint origin; + + QgsComposerLabel* parameterLabel = 0; + //transformation that involves only scaling and rotation (linear or helmert) ? + bool wldTransform = transform.getOriginRotationScale( origin, scaleX, scaleY, rotation ); + + //consider rotation in scale parameter + double wldScaleX = scaleX; + double wldScaleY = scaleY; + if ( wldTransform && !doubleNear( rotation, 0.0 ) ) + { + wldScaleX *= cos( rotation ); + wldScaleY *= cos( rotation ); + } + + if ( wldTransform ) + { + parameterLabel = new QgsComposerLabel( composition ); + parameterLabel->setText( tr( "Transformation parameters" ) ); + parameterLabel->adjustSizeToText(); + composition->addItem( parameterLabel ); + parameterLabel->setSceneRect( QRectF( 10, composerMap->rect().bottom() + composerMap->transform().dy() + 5, composition->paperWidth(), 8 ) ); + parameterLabel->setFrame( false ); + + //calculate mean error (in map units) + double meanError = 0; + if ( mPoints.size() > 4 ) + { + double sumVxSquare = 0; + double sumVySquare = 0; + double resXMap, resYMap; + + int nPointsEnabled = 0; + QgsGCPList::const_iterator gcpIt = mPoints.constBegin(); + for ( ; gcpIt != mPoints.constEnd(); ++gcpIt ) + { + if (( *gcpIt )->isEnabled() ) + { + resXMap = ( *gcpIt )->residual().x() * wldScaleX; + resYMap = ( *gcpIt )->residual().x() * wldScaleY; + sumVxSquare += ( resXMap * resXMap ); + sumVySquare += ( resYMap * resYMap ); + ++nPointsEnabled; + } + } + + if ( nPointsEnabled > 4 ) + { + meanError = sqrt(( sumVxSquare + sumVySquare ) / ( 2 * nPointsEnabled - 4 ) ) * sqrt( 2 ); + } + } + + + parameterTable = new QgsComposerTextTable( composition ); + QStringList headers; + headers << tr( "Translation x" ) << tr( "Translation y" ) << tr( "Scale x" ) << tr( "Scale y" ) << tr( "Rotation [degrees]" ) << tr( "Mean error [map units]" ); + parameterTable->setHeaderLabels( headers ); + QStringList row; + row << QString::number( origin.x() ) << QString::number( origin.y() ) << QString::number( scaleX ) << QString::number( scaleY ) << QString::number( rotation * 180 / M_PI ) << QString::number( meanError ); + parameterTable->addRow( row ); + composition->addItem( parameterTable ); + parameterTable->setSceneRect( QRectF( 10, parameterLabel->rect().bottom() + parameterLabel->transform().dy() + 5, 50, 20 ) ); + parameterTable->setGridStrokeWidth( 0.1 ); + parameterTable->adjustFrameToSize(); + } + + QGraphicsRectItem* previousItem = composerMap; + if ( parameterTable ) + { + previousItem = parameterTable; + } + + QgsComposerLabel* residualLabel = new QgsComposerLabel( composition ); + residualLabel->setText( tr( "Residuals" ) ); + composition->addItem( residualLabel ); + residualLabel->setSceneRect( QRectF( 10, previousItem->rect().bottom() + previousItem->transform().dy() + 5, composition->paperWidth(), 6 ) ); + residualLabel->setFrame( false ); + + //residual plot + QgsResidualPlotItem* resPlotItem = new QgsResidualPlotItem( composition ); + composition->addItem( resPlotItem ); + resPlotItem->setSceneRect( QRectF( 10, residualLabel->rect().bottom() + residualLabel->transform().dy() + 5, composerMap->rect().width(), composerMap->rect().height() ) ); + resPlotItem->setExtent( composerMap->extent() ); + resPlotItem->setGCPList( mPoints ); + + //convert residual scale bar plot to map units if scaling is equal in x- and y-direction (e.g. helmert) + if ( wldTransform ) + { + if ( doubleNear( wldScaleX, wldScaleY ) ) + { + resPlotItem->setPixelToMapUnits( scaleX ); + resPlotItem->setConvertScaleToMapUnits( true ); + } + } + + QString residualUnits; + if ( wldTransform ) + { + residualUnits = tr( "map units" ); + } + else + { + residualUnits = tr( "pixels" ); + } + QgsComposerTextTable* gcpTable = new QgsComposerTextTable( composition ); + QStringList gcpHeader; + gcpHeader << "id" << "enabled" << "pixelCoordX" << "pixelCoordY" << "mapCoordX" << "mapCoordY" << "resX[" + residualUnits + "]" << "resY[" + residualUnits + "]" << "resTot[" + residualUnits + "]"; + gcpTable->setHeaderLabels( gcpHeader ); + + QgsGCPList::const_iterator gcpIt = mPoints.constBegin(); + for ( ; gcpIt != mPoints.constEnd(); ++gcpIt ) + { + QStringList currentGCPStrings; + QPointF residual = ( *gcpIt )->residual(); + double residualX = residual.x(); + if ( wldTransform ) + { + residualX *= wldScaleX; + } + double residualY = residual.y(); + if ( wldTransform ) + { + residualY *= wldScaleY; + } + double residualTot = sqrt( residualX * residualX + residualY * residualY ); + + currentGCPStrings << QString::number(( *gcpIt )->id() ); + if (( *gcpIt )->isEnabled() ) + { + currentGCPStrings << tr( "yes" ); + } + else + { + currentGCPStrings << tr( "no" ); + } + currentGCPStrings << QString::number(( *gcpIt )->pixelCoords().x() ) << QString::number(( *gcpIt )->pixelCoords().y() ) << QString::number(( *gcpIt )->mapCoords().x() )\ + << QString::number(( *gcpIt )->mapCoords().y() ) << QString::number( residualX ) << QString::number( residualY ) << QString::number( residualTot ); + gcpTable->addRow( currentGCPStrings ); + } + + composition->addItem( gcpTable ); + + gcpTable->setSceneRect( QRectF( 10, resPlotItem->rect().bottom() + resPlotItem->transform().dy() + 5, 170, 100 ) ); + gcpTable->setGridStrokeWidth( 0.1 ); + + printer.setResolution( composition->printResolution() ); + QPainter p( &printer ); + composition->setPlotStyle( QgsComposition::Print ); + QRectF paperRectMM = printer.pageRect( QPrinter::Millimeter ); + QRectF paperRectPixel = printer.pageRect( QPrinter::DevicePixel ); + composition->render( &p, paperRectPixel, paperRectMM ); + + delete titleLabel; + delete parameterLabel; + delete residualLabel; + delete resPlotItem; + delete parameterTable; + delete gcpTable; + delete composerMap; + delete composition; + return true; +} + // Gdal script void QgsGeorefPluginGui::showGDALScript( int argNum... ) { @@ -1181,7 +1470,7 @@ QFileInfo rasterFileInfo( mRasterFileName ); mTranslatedRasterFileName = QDir::tempPath() + "/" + rasterFileInfo.fileName(); - gdalCommand << QString("\"%1\"").arg(mRasterFileName) << QString("\"%1\"").arg(mTranslatedRasterFileName); + gdalCommand << QString( "\"%1\"" ).arg( mRasterFileName ) << QString( "\"%1\"" ).arg( mTranslatedRasterFileName ); return gdalCommand.join( " " ); } @@ -1191,8 +1480,8 @@ { QStringList gdalCommand; gdalCommand << "gdalwarp" << "-r" << resampling; - - if (order > 0 && order <= 3) + + if ( order > 0 && order <= 3 ) { // Let gdalwarp use polynomial warp with the given degree gdalCommand << "-order" << QString::number( order ); @@ -1202,14 +1491,14 @@ // Otherwise, use thin plate spline interpolation gdalCommand << "-tps"; } - gdalCommand<< "-co COMPRESS=" + compress << ( useZeroForTrans ? "-dstalpha" : "" ); + gdalCommand << "-co COMPRESS=" + compress << ( useZeroForTrans ? "-dstalpha" : "" ); if ( targetResX != 0.0 && targetResY != 0.0 ) { gdalCommand << "-tr" << QString::number( targetResX, 'f' ) << QString::number( targetResY, 'f' ); } - gdalCommand << QString("\"%1\"").arg(mTranslatedRasterFileName) << QString("\"%1\"").arg(mModifiedRasterFileName); + gdalCommand << QString( "\"%1\"" ).arg( mTranslatedRasterFileName ) << QString( "\"%1\"" ).arg( mModifiedRasterFileName ); return gdalCommand.join( " " ); } @@ -1248,7 +1537,8 @@ continue; } - if ( mModifiedRasterFileName.isEmpty() && QgsGeorefTransform::Linear != mTransformParam ) + //MH: helmert transformation without warping disabled until qgis is able to read rotated rasters efficiently + if ( mModifiedRasterFileName.isEmpty() && QgsGeorefTransform::Linear != mTransformParam /*&& QgsGeorefTransform::Helmert != mTransformParam*/ ) { QMessageBox::information( this, tr( "Info" ), tr( "Please set output raster name" ) ); if ( !getTransformSettings() ) Index: src/plugins/georeferencer/qgsresidualplotitem.h =================================================================== --- src/plugins/georeferencer/qgsresidualplotitem.h (revision 0) +++ src/plugins/georeferencer/qgsresidualplotitem.h (revision 0) @@ -0,0 +1,51 @@ +#ifndef QGSRESIDUALPLOTITEM_H +#define QGSRESIDUALPLOTITEM_H + +#include "qgscomposeritem.h" +#include "qgsgcplist.h" +#include "qgsrectangle.h" + +/**A composer item to visualise the distribution of georeference residuals. For the visualisation, \ +the length of the residual arrows are scaled*/ +class QgsResidualPlotItem: public QgsComposerItem +{ + public: + QgsResidualPlotItem( QgsComposition* c ); + ~QgsResidualPlotItem(); + + /** \brief Reimplementation of QCanvasItem::paint*/ + virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget ); + + void setGCPList( const QgsGCPList& list ) { mGCPList = list; } + QgsGCPList GCPList() const { return mGCPList; } + + void setExtent( const QgsRectangle& rect ) { mExtent = rect;} + QgsRectangle extent() const { return mExtent; } + + void setPixelToMapUnits( double d ) { mPixelToMapUnits = d; } + double pixelToMapUnits() const { return mPixelToMapUnits; } + + void setConvertScaleToMapUnits( bool convert ) { mConvertScaleToMapUnits = convert; } + bool convertScaleToMapUnits() const { return mConvertScaleToMapUnits; } + + virtual bool writeXML( QDomElement& elem, QDomDocument & doc ) const; + virtual bool readXML( const QDomElement& itemElem, const QDomDocument& doc ); + + private: + //gcp list + QgsGCPList mGCPList; + + QgsRectangle mExtent; + /**True if the scale bar units should be converted to map units. This can be done for transformation where the scaling in all directions is the same (helmert)*/ + bool mConvertScaleToMapUnits; + /**Scale factor from pixels to map units*/ + double mPixelToMapUnits; + + /**Calculates maximal possible mm to pixel ratio such that the residual arrow is still inside the frame*/ + double maxMMToPixelRatioForGCP( const QgsGeorefDataPoint* p, double pixelXMM, double pixelYMM ); + + /**Returns distance between two points*/ + double dist( const QPointF& p1, const QPointF& p2 ) const; +}; + +#endif // QGSRESIDUALPLOTITEM_H Index: src/plugins/georeferencer/qgstransformsettingsdialogbase.ui =================================================================== --- src/plugins/georeferencer/qgstransformsettingsdialogbase.ui (revision 13350) +++ src/plugins/georeferencer/qgstransformsettingsdialogbase.ui (working copy) @@ -6,19 +6,16 @@ 0 0 - 307 - 328 + 356 + 381 Transformation settings - - - - - QFormLayout::ExpandingFieldsGrow - + + + @@ -161,27 +158,61 @@ + + + Generate pdf report: + + + + + + + + + + + + ... + + + + + + Set Target Resolution - + Horizontal - + + + + 5 + + + 0.000000000000000 + + + 999999.000000000000000 + + + + Vertical - + @@ -203,22 +234,9 @@ - - - - 5 - - - 0.000000000000000 - - - 999999.000000000000000 - - - - + Use 0 for transparency when needed @@ -228,14 +246,14 @@ - + Load in QGIS when done - + Qt::Horizontal Index: src/plugins/georeferencer/qgsgeoreftransform.cpp =================================================================== --- src/plugins/georeferencer/qgsgeoreftransform.cpp (revision 13350) +++ src/plugins/georeferencer/qgsgeoreftransform.cpp (working copy) @@ -71,6 +71,7 @@ double angle; }; + bool getOriginScaleRotation( QgsPoint &origin, double& scale, double& rotation ) const; bool updateParametersFromGCPs( const std::vector &mapCoords, const std::vector &pixelCoords ); uint getMinimumGCPCount() const; @@ -246,7 +247,29 @@ return dynamic_cast( mGeorefTransformImplementation )->getOriginScale( origin, scaleX, scaleY ); } +bool QgsGeorefTransform::getOriginRotationScale( QgsPoint &origin, double &scaleX, double &scaleY, double& rotation ) const +{ + if ( mTransformParametrisation == Linear ) + { + rotation = 0.0; + return dynamic_cast( mGeorefTransformImplementation )->getOriginScale( origin, scaleX, scaleY ); + } + else if ( mTransformParametrisation == Helmert ) + { + double scale; + if ( ! dynamic_cast( mGeorefTransformImplementation )->getOriginScaleRotation( origin, scale, rotation ) ) + { + return false; + } + scaleX = scale; + scaleY = scale; + return true; + } + return false; +} + + bool QgsGeorefTransform::gdal_transform( const QgsPoint &src, QgsPoint &dst, int dstToSrc ) const { GDALTransformerFunc t = GDALTransformer(); @@ -357,6 +380,13 @@ return ( void* )&mHelmertParameters; } +bool QgsHelmertGeorefTransform::getOriginScaleRotation( QgsPoint &origin, double& scale, double& rotation ) const +{ + origin = mHelmertParameters.origin; + scale = mHelmertParameters.scale; + rotation = mHelmertParameters.angle; + return true; +} int QgsHelmertGeorefTransform::helmert_transform( void *pTransformerArg, int bDstToSrc, int nPointCount, double *x, double *y, double *z, int *panSuccess ) Index: src/plugins/georeferencer/qgsgeorefdatapoint.cpp =================================================================== --- src/plugins/georeferencer/qgsgeorefdatapoint.cpp (revision 13350) +++ src/plugins/georeferencer/qgsgeorefdatapoint.cpp (working copy) @@ -47,6 +47,8 @@ mPixelCoords = p.pixelCoords(); mMapCoords = p.mapCoords(); mEnabled = p.isEnabled(); + mResidual = p.residual(); + mId = p.id(); } QgsGeorefDataPoint::~QgsGeorefDataPoint() Index: src/plugins/georeferencer/qgstransformsettingsdialog.h =================================================================== --- src/plugins/georeferencer/qgstransformsettingsdialog.h (revision 13350) +++ src/plugins/georeferencer/qgstransformsettingsdialog.h (working copy) @@ -32,7 +32,7 @@ int countGCPpoints, QWidget *parent = 0 ); void getTransformSettings( QgsGeorefTransform::TransformParametrisation &tp, QgsImageWarper::ResamplingMethod &rm, QString &comprMethod, - QString &raster, QString &proj, bool &zt, bool &loadInQgis, + QString &raster, QString &proj, QString& pdfReportFile, bool &zt, bool &loadInQgis, double& resX, double& resY ); static void resetSettings(); @@ -43,6 +43,7 @@ private slots: void on_tbnOutputRaster_clicked(); void on_tbnTargetSRS_clicked(); + void on_tbnReportFile_clicked(); void on_leTargetSRS_textChanged( const QString &text ); QIcon getThemeIcon( const QString &theName );