Skip to content

Commit 06ce53e

Browse files
author
mmassing
committedFeb 14, 2010
Merge with WARP_REFACTORING branch, which refactors and adds infrastructure for
gcp fitting and residual error reporting. Part 1/2 of new georeferencer. git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@12944 c8812cc2-4d05-0410-92ff-de0c093fc19c

21 files changed

+1908
-649
lines changed
 

‎src/plugins/georeferencer/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,33 @@
33

44
SET (GEOREF_SRCS
55
qgsgeorefplugin.cpp
6+
qgsgcplistmodel.cpp
67
qgsgeorefdatapoint.cpp
78
qgsimagewarper.cpp
89
qgsleastsquares.cpp
910
qgspointdialog.cpp
1011
qgsgeorefdescriptiondialog.cpp
1112
qgsgeorefwarpoptionsdialog.cpp
13+
qgsgeoreftransform.cpp
1214
mapcoordsdialog.cpp
15+
qgsgcplistwidget.cpp
1316
)
1417

1518
SET (GEOREF_UIS
1619
qgspointdialogbase.ui
1720
mapcoordsdialogbase.ui
1821
qgsgeorefdescriptiondialogbase.ui
1922
qgsgeorefwarpoptionsdialogbase.ui
23+
qgsgcplistwidgetbase.ui
2024
)
2125

2226
SET (GEOREF_MOC_HDRS
27+
# qgsgcplistmodel.h
2328
qgsgeorefplugin.h
2429
qgspointdialog.h
2530
mapcoordsdialog.h
2631
qgsgeorefwarpoptionsdialog.h
32+
qgsgcplistwidget.h
2733
)
2834

2935
SET (GEOREF_RCCS georeferencer.qrc)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/***************************************************************************
2+
qgsgcplist.h - GCP list class
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+
/* $Id */
16+
17+
#ifndef QGS_GCP_LIST_H
18+
#define QGS_GCP_LIST_H
19+
20+
#include <vector>
21+
22+
class QgsGeorefDataPoint;
23+
24+
typedef std::vector<QgsGeorefDataPoint *> QgsGCPList;
25+
26+
#endif
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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+
/* $Id */
16+
#include "qgsgcplistmodel.h"
17+
18+
#include "qgsgeorefdatapoint.h"
19+
#include "qgsgeoreftransform.h"
20+
21+
#include <cmath>
22+
using namespace std;
23+
24+
template <class T> class QNumericItem : public QStandardItem {
25+
public:
26+
QNumericItem(T value) : QStandardItem(QString("%1").arg(value)), mValue(value)
27+
{
28+
}
29+
30+
bool operator < (const QStandardItem &other) const
31+
{
32+
const QNumericItem<T> *otherD = dynamic_cast<const QNumericItem<T> *>(&other);
33+
if (otherD == NULL)
34+
return false;
35+
return mValue < otherD->mValue;
36+
}
37+
private:
38+
T mValue;
39+
};
40+
41+
QgsGCPListModel::QgsGCPListModel(QObject *parent) : QStandardItemModel(parent), mGCPList(0), mGeorefTransform(0)
42+
{
43+
}
44+
45+
void QgsGCPListModel::setGCPList(QgsGCPList *theGCPList)
46+
{
47+
mGCPList = theGCPList;
48+
updateModel(true);
49+
}
50+
51+
void QgsGCPListModel::setGeorefTransform(QgsGeorefTransform *theGeorefTransform)
52+
{
53+
mGeorefTransform = theGeorefTransform;
54+
updateModel(true);
55+
}
56+
57+
void QgsGCPListModel::onGCPListModified()
58+
{
59+
}
60+
61+
void QgsGCPListModel::onTransformationModified()
62+
{
63+
}
64+
65+
template <class T> QNumericItem<T> *create_item(const T value, bool isEditable = false)
66+
{
67+
QNumericItem<T> *item = new QNumericItem<T>(value);
68+
item->setEditable(isEditable);
69+
return item;
70+
}
71+
72+
QStandardItem *create_std_item(const QString &S, bool isEditable = false)
73+
{
74+
QStandardItem *std_item = new QStandardItem(S);
75+
std_item->setEditable(isEditable);
76+
return std_item;
77+
}
78+
79+
void QgsGCPListModel::updateModel(bool gcpsDirty)
80+
{
81+
clear();
82+
if (!mGCPList)
83+
return;
84+
85+
// Setup table header
86+
QStringList itemLabels;
87+
// Set column headers
88+
itemLabels<<"id"<<"srcX"<<"srcY"<<"dstX"<<"dstY"<<"dX"<<"dY"<<"residual";
89+
setColumnCount(itemLabels.size());
90+
setHorizontalHeaderLabels(itemLabels);
91+
92+
setRowCount(mGCPList->size());
93+
94+
95+
if (gcpsDirty && mGeorefTransform)
96+
{
97+
vector<QgsPoint> rC, mC;
98+
// TODO: move this vector extraction snippet into QgsGCPList
99+
for (int i = 0; i < mGCPList->size(); i++) {
100+
rC.push_back((*mGCPList)[i]->pixelCoords());
101+
mC.push_back((*mGCPList)[i]->mapCoords());
102+
}
103+
104+
// TODO: the parameters should probable be updated externally (by user interaction)
105+
mGeorefTransform->updateParametersFromGCPs(mC, rC);
106+
}
107+
108+
for (int i = 0; i < mGCPList->size(); i++)
109+
{
110+
int j = 0;
111+
QgsGeorefDataPoint &p = *(*mGCPList)[i];
112+
113+
setItem(i, j++, create_item<int>(i));
114+
setItem(i, j++, create_item<double>( p.pixelCoords().x() ));
115+
setItem(i, j++, create_item<double>(-p.pixelCoords().y() ));
116+
setItem(i, j++, create_item<double>( p.mapCoords().x() ));
117+
setItem(i, j++, create_item<double>( p.mapCoords().y() ));
118+
119+
double residual = -1.f;
120+
double dX, dY;
121+
// Calculate residual if transform is available and up-to-date
122+
if (mGeorefTransform && mGeorefTransform->parametersInitialized())
123+
{
124+
QgsPoint dst;
125+
// Transform from world to raster coordinate:
126+
// This is the transform direction used by the warp operation.
127+
// As transforms of order >=2 are not invertible, we are only
128+
// interested in the residual in this direction
129+
mGeorefTransform->transformWorldToRaster(p.mapCoords(), dst);
130+
dX = (dst.x() - p.pixelCoords().x());
131+
dY = (dst.y() - p.pixelCoords().y());
132+
residual = sqrt(dX*dX + dY*dY);
133+
}
134+
if (residual >= 0.f) {
135+
setItem(i, j++, create_item<double>(dX));
136+
setItem(i, j++, create_item<double>(-dY));
137+
setItem(i, j++, create_item<double>(residual));
138+
}
139+
else {
140+
setItem(i, j++, create_std_item("n/a"));
141+
setItem(i, j++, create_std_item("n/a"));
142+
setItem(i, j++, create_std_item("n/a"));
143+
}
144+
}
145+
//sort(); // Sort data
146+
//reset(); // Signal to views that the model has changed
147+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/***************************************************************************
2+
qgsgcplistmodel.h - 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+
#ifndef QGSGCP_LIST_TABLE_VIEW_H
17+
#define QGSGCP_LIST_TABLE_VIEW_H
18+
19+
#include <QTreeView>
20+
#include <QStandardItemModel>
21+
22+
#include "qgsgcplist.h"
23+
24+
class QgsGeorefTransform;
25+
//class QgsGCPList;
26+
//^^currently a typedef, so no forward dec possible
27+
28+
29+
class QgsGCPListModel : public QStandardItemModel {
30+
//Q_OBJECT
31+
public:
32+
QgsGCPListModel(QObject *parent = NULL);
33+
34+
void setGCPList(QgsGCPList *theGCPList);
35+
void setGeorefTransform(QgsGeorefTransform *theGeorefTransform);
36+
public slots:
37+
void onGCPListModified();
38+
void onTransformationModified();
39+
private:
40+
void updateModel(bool gcpsDirty);
41+
42+
QgsGCPList *mGCPList;
43+
QgsGeorefTransform *mGeorefTransform;
44+
};
45+
46+
#endif
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/***************************************************************************
2+
qgsgcplistwidget.cpp - Widget for GCP list display
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+
/* $Id */
16+
17+
#include <QHeaderView>
18+
19+
#include "qgsgcplistwidget.h"
20+
#include "qgsgcplistmodel.h"
21+
22+
#include "qgspointdialog.h"
23+
24+
#include <iostream> //debugging
25+
26+
QgsGCPListWidget::QgsGCPListWidget(QWidget *parent) : QWidget(parent)
27+
{
28+
setupUi(this);
29+
initialize();
30+
}
31+
32+
void QgsGCPListWidget::initialize()
33+
{
34+
mGCPListModel = new QgsGCPListModel;
35+
mGCPTableView->setModel(mGCPListModel);
36+
mGCPTableView->setSortingEnabled(true);
37+
mGCPTableView->verticalHeader()->hide();
38+
39+
connect(mGCPTableView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(itemDoubleClicked(const QModelIndex &)));
40+
}
41+
42+
void QgsGCPListWidget::setGCPList(QgsGCPList *theGCPList)
43+
{
44+
mGCPListModel->setGCPList(theGCPList);
45+
}
46+
47+
void QgsGCPListWidget::setGeorefTransform(QgsGeorefTransform *theGeorefTransform)
48+
{
49+
mGCPListModel->setGeorefTransform(theGeorefTransform);
50+
}
51+
52+
void QgsGCPListWidget::itemDoubleClicked(const QModelIndex &index)
53+
{
54+
QStandardItem *item = mGCPListModel->item(index.row(), 0);
55+
bool ok;
56+
int id = item->text().toInt(&ok);
57+
58+
if (ok)
59+
{
60+
emit jumpToGCP(id);
61+
}
62+
}
63+
64+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/***************************************************************************
2+
qgsgcplistwidget.h - Widget for GCP list display
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+
/* $Id */
16+
#ifndef QGS_GCP_LIST_WIDGET_H
17+
#define QGS_GCP_LIST_WIDGET_H
18+
19+
#include <QWidget>
20+
#include "ui_qgsgcplistwidgetbase.h"
21+
#include "qgsgcplist.h"
22+
23+
//class QgsGCPList;
24+
class QgsGCPListModel;
25+
class QgsGeorefTransform;
26+
27+
class QgsGCPListWidget : public QWidget, private Ui::QgsGCPListWidgetBase {
28+
Q_OBJECT
29+
public:
30+
QgsGCPListWidget(QWidget *parent = 0);
31+
32+
void setGCPList(QgsGCPList *theGCPList);
33+
void setGeorefTransform(QgsGeorefTransform *theGeorefTransform);
34+
public slots:
35+
// This slot is called by the list view if an item is double-clicked
36+
void itemDoubleClicked(const QModelIndex &);
37+
signals:
38+
void jumpToGCP(uint theGCPIndex);
39+
private:
40+
void initialize();
41+
42+
QgsGCPList *mGCPList;
43+
QgsGCPListModel *mGCPListModel;
44+
};
45+
46+
#endif
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<ui version="4.0" >
2+
<class>QgsGCPListWidgetBase</class>
3+
<widget class="QWidget" name="QgsGCPListWidgetBase" >
4+
<property name="geometry" >
5+
<rect>
6+
<x>0</x>
7+
<y>0</y>
8+
<width>584</width>
9+
<height>412</height>
10+
</rect>
11+
</property>
12+
<property name="windowTitle" >
13+
<string>GCP List</string>
14+
</property>
15+
<layout class="QVBoxLayout" name="verticalLayout" >
16+
<item>
17+
<layout class="QGridLayout" name="gridLayout" >
18+
<item row="0" column="0" >
19+
<widget class="QTableView" name="mGCPTableView" />
20+
</item>
21+
</layout>
22+
</item>
23+
</layout>
24+
</widget>
25+
<resources/>
26+
<connections/>
27+
</ui>

‎src/plugins/georeferencer/qgsgeorefdatapoint.cpp

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,79 @@
1616
#include "qgsgeorefdatapoint.h"
1717
#include "qgsmapcanvas.h"
1818

19-
QgsGeorefDataPoint::QgsGeorefDataPoint( QgsMapCanvas* mapCanvas, int id,
19+
class QgsGCPCanvasItem : public QgsMapCanvasItem {
20+
public:
21+
QgsGCPCanvasItem( QgsMapCanvas* mapCanvas, const QgsPoint& rasterCoords, const QgsPoint& worldCoords, bool isGCPSource = true );
22+
23+
//! draws point information
24+
virtual void paint( QPainter* p );
25+
26+
//! handler for manual updating of position and size
27+
virtual QRectF boundingRect() const;
28+
29+
virtual void updatePosition();
30+
private:
31+
bool mIsGCPSource;
32+
QSizeF mTextBounds;
33+
QgsPoint mRasterCoords, mWorldCoords;
34+
};
35+
36+
QgsGeorefDataPoint::QgsGeorefDataPoint( QgsMapCanvas* srcCanvas, QgsMapCanvas *dstCanvas, int id,
2037
const QgsPoint& pixelCoords, const QgsPoint& mapCoords )
21-
: QgsMapCanvasItem( mapCanvas ), mId( id ),
22-
mPixelCoords( pixelCoords ), mMapCoords( mapCoords )
38+
: mId( id ), mPixelCoords( pixelCoords ), mMapCoords( mapCoords )
39+
{
40+
mGCPSourceItem = new QgsGCPCanvasItem(srcCanvas, pixelCoords, mapCoords, true);
41+
mGCPDestinationItem = new QgsGCPCanvasItem(dstCanvas, pixelCoords, mapCoords, false);
42+
mGCPSourceItem->show();
43+
mGCPDestinationItem->show();
44+
}
45+
46+
QgsGeorefDataPoint::~QgsGeorefDataPoint()
2347
{
48+
delete mGCPSourceItem;
49+
delete mGCPDestinationItem;
50+
}
51+
52+
53+
QgsGCPCanvasItem::QgsGCPCanvasItem(QgsMapCanvas* mapCanvas, const QgsPoint& rasterCoords, const QgsPoint& worldCoords,
54+
bool isGCPSource ) : QgsMapCanvasItem( mapCanvas )
55+
{
56+
mRasterCoords = rasterCoords;
57+
mWorldCoords = worldCoords;
58+
mIsGCPSource = isGCPSource;
2459
updatePosition();
2560
}
2661

2762

28-
void QgsGeorefDataPoint::paint( QPainter* p )
63+
64+
void QgsGCPCanvasItem::paint( QPainter* p )
2965
{
30-
QString msg = QString( "X %1\nY %2" ).arg( QString::number( mMapCoords.x(), 'f' ) ).arg( QString::number( mMapCoords.y(), 'f' ) );
31-
QFont font;
32-
p->setFont( QFont( "helvetica", 9 ) );
66+
// draw the point
3367
p->setPen( Qt::black );
3468
p->setBrush( Qt::red );
3569
p->drawRect( -2, -2, 5, 5 );
36-
QRect textBounds = p->boundingRect( 4, 4, 10, 10, Qt::AlignLeft, msg );
37-
p->setBrush( Qt::yellow );
38-
p->drawRect( 2, 2, textBounds.width() + 4, textBounds.height() + 4 );
39-
p->drawText( textBounds, Qt::AlignLeft, msg );
40-
41-
mTextBounds = QSizeF( textBounds.width(), textBounds.height() );
70+
71+
if (mIsGCPSource)
72+
{
73+
QString msg = QString( "X %1\nY %2" ).arg( QString::number( mWorldCoords.x(), 'f' ) ).arg( QString::number( mWorldCoords.y(), 'f' ) );
74+
QFont font;
75+
p->setFont( QFont( "helvetica", 9 ) );
76+
QRect textBounds = p->boundingRect( 4, 4, 10, 10, Qt::AlignLeft, msg );
77+
p->setBrush( Qt::yellow );
78+
p->drawRect( 2, 2, textBounds.width() + 4, textBounds.height() + 4 );
79+
p->drawText( textBounds, Qt::AlignLeft, msg );
80+
mTextBounds = QSizeF(textBounds.width() + 4, textBounds.height() + 4);
81+
}
82+
else
83+
mTextBounds = QSizeF(0, 0);
4284
}
4385

44-
QRectF QgsGeorefDataPoint::boundingRect() const
86+
QRectF QgsGCPCanvasItem::boundingRect() const
4587
{
46-
return QRectF( -2, -2, mTextBounds.width() + 6, mTextBounds.height() + 6 );
88+
return QRectF( -2, -2, mTextBounds.width() + 2, mTextBounds.height() + 2 );
4789
}
4890

49-
void QgsGeorefDataPoint::updatePosition()
91+
void QgsGCPCanvasItem::updatePosition()
5092
{
51-
setPos( toCanvasCoordinates( mPixelCoords ) );
93+
setPos( toCanvasCoordinates( mIsGCPSource ? mRasterCoords : mWorldCoords) );
5294
}

‎src/plugins/georeferencer/qgsgeorefdatapoint.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,28 @@
1414
***************************************************************************/
1515
#include "qgsmapcanvasitem.h"
1616

17+
class QgsGCPCanvasItem;
1718

18-
class QgsGeorefDataPoint : public QgsMapCanvasItem
19+
class QgsGeorefDataPoint
1920
{
2021
public:
2122

2223
//! constructor
23-
QgsGeorefDataPoint( QgsMapCanvas* mapCanvas, int id,
24+
QgsGeorefDataPoint( QgsMapCanvas *srcCanvas, QgsMapCanvas *dstCanvas, int id,
2425
const QgsPoint& pixelCoords,
2526
const QgsPoint& mapCoords );
2627

27-
//! draws point information
28-
virtual void paint( QPainter* p );
28+
~QgsGeorefDataPoint();
2929

30-
//! handler for manual updating of position and size
31-
virtual QRectF boundingRect() const;
32-
33-
virtual void updatePosition();
3430

3531
//! returns coordinates of the point
36-
QgsPoint pixelCoords() { return mPixelCoords; }
37-
QgsPoint mapCoords() { return mMapCoords; }
32+
QgsPoint pixelCoords() const { return mPixelCoords; }
33+
QgsPoint mapCoords() const { return mMapCoords; }
3834

3935
private:
36+
QgsGCPCanvasItem *mGCPSourceItem;
37+
QgsGCPCanvasItem *mGCPDestinationItem;
4038
int mId;
4139
QgsPoint mPixelCoords;
4240
QgsPoint mMapCoords;
43-
QSizeF mTextBounds;
4441
};
45-

‎src/plugins/georeferencer/qgsgeorefdescriptiondialogbase.ui

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
<string>Description georeferencer</string>
1414
</property>
1515
<property name="windowIcon" >
16+
<iconset>
17+
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
1618
</property>
1719
<property name="modal" >
1820
<bool>true</bool>
@@ -39,6 +41,14 @@
3941
<property name="readOnly" >
4042
<bool>true</bool>
4143
</property>
44+
<property name="html" >
45+
<string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
46+
&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
47+
p, li { white-space: pre-wrap; }
48+
&lt;/style>&lt;/head>&lt;body style=" font-family:'Verdana'; font-size:9pt; font-weight:400; font-style:normal;">
49+
&lt;p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Description&lt;/p>
50+
&lt;p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This plugin can generate world files for rasters. You select points on the raster and give their world coordinates, and the plugin will compute the world file parameters. The more coordinates you can provide the better the result will be.&lt;/p>&lt;/body>&lt;/html></string>
51+
</property>
4252
</widget>
4353
</item>
4454
<item row="0" column="0" >

‎src/plugins/georeferencer/qgsgeorefplugin.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* (at your option) any later version. *
1919
* *
2020
***************************************************************************/
21-
/* $Id$ */
21+
/* $Id: plugin.cpp 9231 2008-08-31 16:56:09Z timlinux $ */
2222

2323
/***************************************************************************
2424
* QGIS Programming conventions:
@@ -57,7 +57,7 @@
5757
#include "qgspointdialog.h"
5858
#include "qgsgeorefdescriptiondialog.h"
5959

60-
static const char * const sIdent = "$Id$";
60+
static const char * const sIdent = "$Id: plugin.cpp 9231 2008-08-31 16:56:09Z timlinux $";
6161
static const QString sName = QObject::tr( "Georeferencer GDAL" );
6262
static const QString sDescription = QObject::tr( "Adding projection info to rasters using GDAL" );
6363
static const QString sPluginVersion = QObject::tr( "Version 0.1" );
@@ -105,15 +105,15 @@ void QgsGeorefPlugin::initGui()
105105
mQGisIface->addToolBarIcon( mQActionPointer );
106106
mQGisIface->addPluginToMenu( tr( "&Georeferencer" ), mQActionPointer );
107107

108-
mQActionPointer = new QAction( QIcon( ":/about.png" ), tr( "&Georeferencer" ), this );
109-
mQActionPointer = new QAction( "About", this );
110-
connect( mQActionPointer, SIGNAL( triggered() ), SLOT( about() ) );
111-
mQGisIface->addPluginToMenu( tr( "&Georeferencer" ), mQActionPointer );
108+
mQActionPointerAbout = new QAction( QIcon( ":/about.png" ), tr( "&About" ), this );
109+
// mQActionPointer = new QAction("About", this);
110+
connect(mQActionPointerAbout, SIGNAL(triggered()), this, SLOT(about()));
111+
mQGisIface->addPluginToMenu(tr ("&Georeferencer"), mQActionPointerAbout);
112112

113-
mQActionPointer = new QAction( QIcon( ":/help.png" ), tr( "&Georeferencer" ), this );
114-
mQActionPointer = new QAction( "Help", this );
115-
connect( mQActionPointer, SIGNAL( triggered() ), SLOT( help() ) );
116-
mQGisIface->addPluginToMenu( tr( "&Georeferencer" ), mQActionPointer );
113+
mQActionPointerHelp = new QAction( QIcon( ":/help.png" ), tr( "&Help" ), this );
114+
// mQActionPointer = new QAction("Help", this);
115+
connect(mQActionPointerHelp, SIGNAL(triggered()), this, SLOT(help()));
116+
mQGisIface->addPluginToMenu(tr ("&Georeferencer"), mQActionPointerHelp);
117117
}
118118
//method defined in interface
119119
void QgsGeorefPlugin::help()
@@ -158,9 +158,17 @@ void QgsGeorefPlugin::run()
158158
void QgsGeorefPlugin::unload()
159159
{
160160
// remove the GUI
161+
disconnect( mQActionPointer, SIGNAL( triggered() ), this, SLOT( run() ) );
162+
disconnect(mQActionPointerAbout, SIGNAL(triggered()), this, SLOT(about()));
163+
disconnect(mQActionPointerHelp, SIGNAL(triggered()), this, SLOT(help()));
161164
mQGisIface->removePluginMenu( tr( "&Georeferencer" ), mQActionPointer );
165+
mQGisIface->removePluginMenu( tr( "&About" ), mQActionPointerAbout );
166+
mQGisIface->removePluginMenu( tr( "&Help" ), mQActionPointerHelp );
162167
mQGisIface->removeToolBarIcon( mQActionPointer );
168+
163169
delete mQActionPointer;
170+
delete mQActionPointerAbout;
171+
delete mQActionPointerHelp;
164172
}
165173

166174
//! Set icons to the current theme

‎src/plugins/georeferencer/qgsgeorefplugin.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* (at your option) any later version. *
1919
* *
2020
***************************************************************************/
21-
/* $Id$ */
21+
/* $Id: plugin.h 9138 2008-08-23 21:37:31Z jef $ */
2222

2323
/***************************************************************************
2424
* QGIS Programming conventions:
@@ -109,6 +109,8 @@ class QgsGeorefPlugin: public QObject, public QgisPlugin
109109
QgisInterface *mQGisIface;
110110
//!pointer to the qaction for this plugin
111111
QAction * mQActionPointer;
112+
QAction * mQActionPointerAbout;
113+
QAction * mQActionPointerHelp;
112114
////////////////////////////////////////////////////////////////////
113115
//
114116
// ADD YOUR OWN MEMBER DECLARATIONS AFTER THIS POINT.....

‎src/plugins/georeferencer/qgsgeoreftransform.cpp

Lines changed: 484 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/***************************************************************************
2+
qgsgeoreftransform.h - Encapsulates GCP-based parameter estimation and
3+
reprojection for different transformation models.
4+
--------------------------------------
5+
Date : 18-Feb-2009
6+
Copyright : (c) 2009 by Manuel Massing
7+
Email : m.massing at warped-space.de
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
/* $Id */
17+
18+
#ifndef QGS_GEOREF_TRANSFORM_H
19+
#define QGS_GEOREF_TRANSFORM_H
20+
21+
#include <gdal_alg.h> // just needed for GDALTransformerFunc, forward?
22+
23+
#include <qgspoint.h>
24+
#include <vector>
25+
#include <stdexcept>
26+
27+
class QgsGeorefTransformInterface {
28+
public:
29+
virtual ~QgsGeorefTransformInterface() { }
30+
31+
virtual bool updateParametersFromGCPs(const std::vector<QgsPoint> &mapCoords, const std::vector<QgsPoint> &pixelCoords) = 0;
32+
33+
/**
34+
* Returns the minimum number of GCPs required for parameter fitting.
35+
*/
36+
virtual uint getMinimumGCPCount() const = 0;
37+
38+
/**
39+
* Return funtion pointer to the GDALTransformer function.
40+
* Used by GDALwarp.
41+
*/
42+
virtual GDALTransformerFunc GDALTransformer() const = 0;
43+
virtual void* GDALTransformerArgs() const = 0;
44+
};
45+
46+
/**
47+
* \brief Transform class for different gcp-based transform methods.
48+
*
49+
* Select transform type via \ref selectTransformParametrisation.
50+
* Initialize and update parameters via \ref updateParametersFromGCPs.
51+
* An initialized instance then provides transform functions and GDALTransformer entry points
52+
* for warping and coordinate remapping.
53+
*
54+
* Delegates to concrete implementations of \ref QgsGeorefInterface. For exception safety,
55+
* this is preferred over using the subclasses directly.
56+
*/
57+
class QgsGeorefTransform : public QgsGeorefTransformInterface {
58+
public:
59+
// GCP based transform methods implemented by subclasses
60+
enum TransformParametrisation {
61+
Linear,
62+
Helmert,
63+
PolynomialOrder1,
64+
PolynomialOrder2,
65+
PolynomialOrder3,
66+
ThinPlateSpline,
67+
InvalidTransform
68+
};
69+
70+
QgsGeorefTransform(TransformParametrisation parametrisation);
71+
QgsGeorefTransform();
72+
~QgsGeorefTransform();
73+
74+
/**
75+
* Switches the used transform type to the given parametrisation.
76+
*/
77+
void selectTransformParametrisation(TransformParametrisation parametrisation);
78+
79+
//! \brief The transform parametrisation currently in use.
80+
TransformParametrisation transformParametrisation() const;
81+
82+
//! \returns whether the parameters of this transform have been initialised by \ref updateParametersFromGCPs
83+
bool parametersInitialized() const;
84+
85+
/**
86+
* \brief Fits transformation parameters to the supplied ground control points.
87+
*
88+
* \returns true on success, false on failure
89+
*/
90+
bool updateParametersFromGCPs(const std::vector<QgsPoint> &mapCoords, const std::vector<QgsPoint> &pixelCoords);
91+
92+
//! \brief Returns the minimum number of GCPs required for parameter fitting.
93+
uint getMinimumGCPCount() const;
94+
95+
/**
96+
* \brief Return funtion pointer to the GDALTransformer function.
97+
*
98+
* Used by the transform routines \ref transform, \ref transformRasterToWorld
99+
* \ref transformWorldToRaster and by the GDAL warping code
100+
* in \ref QgsImageWarper::warpFile.
101+
*/
102+
GDALTransformerFunc GDALTransformer() const;
103+
void* GDALTransformerArgs() const;
104+
105+
/**
106+
* \brief Transform from pixel coordinates to georeferenced coordinates.
107+
*
108+
* \note Negative y-axis points down in raster CS.
109+
*/
110+
bool transformRasterToWorld(const QgsPoint &raster, QgsPoint &world) const;
111+
112+
/**
113+
* \brief Transform from referenced coordinates to raster coordinates.
114+
*
115+
* \note Negative y-axis points down in raster CS.
116+
*/
117+
bool transformWorldToRaster(const QgsPoint &world, QgsPoint &raster) const;
118+
119+
/**
120+
* \brief Transforms from raster to world if rasterToWorld is true,
121+
* \brief or from world to raster when rasterToWorld is false.
122+
*
123+
* \note Negative y-axis points down in raster CS.
124+
*/
125+
bool transform(const QgsPoint &src, QgsPoint &dst, bool rasterToWorld) const;
126+
127+
//! \brief Returns origin and scale if this is a linear transform, fails otherwise.
128+
bool getLinearOriginScale(QgsPoint &origin, double &scaleX, double &scaleY) const;
129+
private:
130+
// shallow copy constructor
131+
QgsGeorefTransform(const QgsGeorefTransform &other);
132+
133+
//! Factory function which creates an implementation for the given parametrisation.
134+
static QgsGeorefTransformInterface *createImplementation(TransformParametrisation parametrisation);
135+
136+
// convenience wrapper around GDALTransformerFunc
137+
bool gdal_transform(const QgsPoint &src, QgsPoint &dst, int dstToSrc) const;
138+
139+
QgsGeorefTransformInterface *mGeorefTransformImplementation;
140+
TransformParametrisation mTransformParametrisation;
141+
bool mParametersInitialized;
142+
};
143+
144+
#endif

‎src/plugins/georeferencer/qgsgeorefwarpoptionsdialog.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,13 @@ void QgsGeorefWarpOptionsDialog::on_buttonBox_accepted()
6262
{
6363
QgsImageWarper::NearestNeighbour,
6464
QgsImageWarper::Bilinear,
65-
QgsImageWarper::Cubic
65+
QgsImageWarper::Cubic,
66+
QgsImageWarper::CubicSpline,
67+
QgsImageWarper::Lanczos
6668
};
6769
resampling = methods[cmbResampling->currentIndex()];
6870
useZeroAsTransparency = cbxZeroAsTrans->isChecked();
69-
close();
71+
accept();
7072
}
7173

7274
void QgsGeorefWarpOptionsDialog::on_buttonBox_rejected()

‎src/plugins/georeferencer/qgsgeorefwarpoptionsdialogbase.ui

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
<string>Cubic</string>
4545
</property>
4646
</item>
47+
<item>
48+
<property name="text" >
49+
<string>Cubic Spline</string>
50+
</property>
51+
</item>
52+
<item>
53+
<property name="text" >
54+
<string>Lanczos</string>
55+
</property>
56+
</item>
4757
</widget>
4858
</item>
4959
<item row="1" column="0">

‎src/plugins/georeferencer/qgsimagewarper.cpp

Lines changed: 168 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,14 @@
2222
#include <gdalwarper.h>
2323

2424
#include <QFile>
25+
#include <QProgressDialog>
2526

2627
#include "qgsimagewarper.h"
28+
#include "qgsgeoreftransform.h"
29+
30+
QgsImageWarper::QgsImageWarper(QWidget *theParent) : mParent(theParent)
31+
{
32+
}
2733

2834
bool QgsImageWarper::openSrcDSAndGetWarpOpt( const QString &input, const QString &output,
2935
const ResamplingMethod &resampling, const GDALTransformerFunc &pfnTransform,
@@ -54,49 +60,31 @@ bool QgsImageWarper::openSrcDSAndGetWarpOpt( const QString &input, const QString
5460
return true;
5561
}
5662

57-
void QgsImageWarper::warp( const QString& input, const QString& output,
58-
double& xOffset, double& yOffset,
59-
ResamplingMethod resampling, bool useZeroAsTrans, const QString& compression )
63+
bool QgsImageWarper::createDestinationDataset(const QString &outputName, GDALDatasetH hSrcDS, GDALDatasetH &hDstDS, uint resX, uint resY, double *adfGeoTransform, bool useZeroAsTrans, const QString& compression)
6064
{
61-
GDALDatasetH hSrcDS;
62-
GDALWarpOptions *psWarpOptions;
63-
openSrcDSAndGetWarpOpt( input, output, resampling, &QgsImageWarper::transform,
64-
hSrcDS, psWarpOptions );
65-
66-
// check the bounds for the warped raster
67-
// order: upper right, lower right, lower left (y points down)
68-
double x[] = { GDALGetRasterXSize( hSrcDS ), GDALGetRasterXSize( hSrcDS ), 0 };
69-
double y[] = { 0, GDALGetRasterYSize( hSrcDS ), GDALGetRasterYSize( hSrcDS ) };
70-
int s[] = { 0, 0, 0 };
71-
TransformParameters tParam = { mAngle, 0, 0 };
72-
transform( &tParam, FALSE, 3, x, y, NULL, s );
73-
double minX = 0, minY = 0, maxX = 0, maxY = 0;
74-
for ( int i = 0; i < 3; ++i )
75-
{
76-
minX = minX < x[i] ? minX : x[i];
77-
minY = minY < y[i] ? minY : y[i];
78-
maxX = maxX > x[i] ? maxX : x[i];
79-
maxY = maxY > y[i] ? maxY : y[i];
80-
}
81-
int newXSize = int( maxX - minX ) + 1;
82-
int newYSize = int( maxY - minY ) + 1;
83-
xOffset = -minX;
84-
yOffset = -minY;
85-
tParam.x0 = xOffset;
86-
tParam.y0 = yOffset;
87-
psWarpOptions->pTransformerArg = &tParam;
88-
8965
// create the output file
9066
GDALDriverH driver = GDALGetDriverByName( "GTiff" );
67+
if (driver == NULL)
68+
{
69+
return false;
70+
}
9171
char **papszOptions = NULL;
9272
papszOptions = CSLSetNameValue( papszOptions, "INIT_DEST", "NO_DATA" );
9373
papszOptions = CSLSetNameValue( papszOptions, "COMPRESS", compression.toAscii() );
94-
GDALDatasetH hDstDS =
95-
GDALCreate( driver,
96-
QFile::encodeName( output ).constData(), newXSize, newYSize,
97-
GDALGetRasterCount( hSrcDS ),
98-
GDALGetRasterDataType( GDALGetRasterBand( hSrcDS, 1 ) ),
99-
papszOptions );
74+
hDstDS = GDALCreate( driver,
75+
QFile::encodeName( outputName ).constData(), resX, resY,
76+
GDALGetRasterCount( hSrcDS ),
77+
GDALGetRasterDataType( GDALGetRasterBand( hSrcDS, 1 ) ),
78+
papszOptions );
79+
if (hDstDS == NULL)
80+
{
81+
return false;
82+
}
83+
84+
if (CE_None != GDALSetGeoTransform(hDstDS, adfGeoTransform))
85+
{
86+
return false;
87+
}
10088

10189
for ( int i = 0; i < GDALGetRasterCount( hSrcDS ); ++i )
10290
{
@@ -109,128 +97,177 @@ void QgsImageWarper::warp( const QString& input, const QString& output,
10997
GDALSetRasterColorTable( hDstBand, cTable );
11098
}
11199

112-
double noData = GDALGetRasterNoDataValue( hSrcBand, NULL );
113-
if ( noData == -1e10 && useZeroAsTrans )
100+
int success;
101+
double noData = GDALGetRasterNoDataValue( hSrcBand, &success );
102+
if (success)
114103
{
115-
GDALSetRasterNoDataValue( hDstBand, 0 );
104+
GDALSetRasterNoDataValue( hDstBand, noData );
116105
}
117-
else
106+
else if (useZeroAsTrans)
118107
{
119-
GDALSetRasterNoDataValue( hDstBand, noData );
108+
GDALSetRasterNoDataValue( hDstBand, 0 );
120109
}
121110
}
111+
return true;
112+
}
113+
114+
bool QgsImageWarper::warpFile( const QString& input, const QString& output, const QgsGeorefTransform &georefTransform,
115+
ResamplingMethod resampling, bool useZeroAsTrans, const QString& compression)
116+
{
117+
if (!georefTransform.parametersInitialized())
118+
return false;
119+
120+
CPLErr eErr;
121+
GDALDatasetH hSrcDS, hDstDS;
122+
GDALWarpOptions *psWarpOptions;
123+
if (!openSrcDSAndGetWarpOpt(input, output, resampling, georefTransform.GDALTransformer(), hSrcDS, psWarpOptions))
124+
{
125+
// TODO: be verbose about failures
126+
return false;
127+
}
128+
129+
double adfGeoTransform[6];
130+
int destPixels, destLines;
131+
eErr = GDALSuggestedWarpOutput(hSrcDS, georefTransform.GDALTransformer(), georefTransform.GDALTransformerArgs(),
132+
adfGeoTransform, &destPixels, &destLines);
133+
if (eErr != CE_None)
134+
{
135+
GDALClose( hSrcDS );
136+
GDALDestroyWarpOptions( psWarpOptions );
137+
return false;
138+
}
139+
140+
if (!createDestinationDataset(output, hSrcDS, hDstDS, destPixels, destLines, adfGeoTransform, useZeroAsTrans, compression))
141+
{
142+
GDALClose( hSrcDS );
143+
GDALDestroyWarpOptions( psWarpOptions );
144+
return false;
145+
}
146+
147+
// Create a QT progress dialog
148+
QProgressDialog *progressDialog = new QProgressDialog(mParent);
149+
progressDialog->setRange(0, 100);
150+
progressDialog->setAutoClose(true);
151+
progressDialog->setModal(true);
152+
progressDialog->setMinimumDuration(0);
153+
154+
// Set GDAL callbacks for the progress dialog
155+
psWarpOptions->pProgressArg = createWarpProgressArg(progressDialog);
156+
psWarpOptions->pfnProgress = updateWarpProgress;
157+
158+
psWarpOptions->hSrcDS = hSrcDS;
122159
psWarpOptions->hDstDS = hDstDS;
123160

161+
// Create a transformer which transforms from source to destination pixels (and vice versa)
162+
psWarpOptions->pfnTransformer = GeoToPixelTransform;
163+
psWarpOptions->pTransformerArg = addGeoToPixelTransform(georefTransform.GDALTransformer(),
164+
georefTransform.GDALTransformerArgs(),
165+
adfGeoTransform);
166+
124167
// Initialize and execute the warp operation.
125168
GDALWarpOperation oOperation;
126169
oOperation.Initialize( psWarpOptions );
127-
oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ),
128-
GDALGetRasterYSize( hDstDS ) );
170+
171+
progressDialog->show();
172+
progressDialog->raise();
173+
progressDialog->activateWindow();
174+
175+
eErr = oOperation.ChunkAndWarpImage(0, 0, destPixels, destLines);
176+
177+
destroyGeoToPixelTransform(psWarpOptions->pTransformerArg);
129178
GDALDestroyWarpOptions( psWarpOptions );
179+
delete progressDialog;
130180

131181
GDALClose( hSrcDS );
132182
GDALClose( hDstDS );
183+
if (eErr != CE_None)
184+
{
185+
return false;
186+
}
187+
return true;
133188
}
134189

135190

136-
int QgsImageWarper::transform( void *pTransformerArg, int bDstToSrc,
137-
int nPointCount, double *x, double *y,
138-
double *z, int *panSuccess )
191+
void *QgsImageWarper::addGeoToPixelTransform(GDALTransformerFunc GDALTransformer, void *GDALTransformerArg, double *padfGeotransform) const
139192
{
140-
TransformParameters* t = static_cast<TransformParameters*>( pTransformerArg );
141-
double a = cos( t->angle ), b = sin( t->angle ), x0 = t->x0, y0 = t->y0;
142-
for ( int i = 0; i < nPointCount; ++i )
193+
TransformChain *chain = new TransformChain;
194+
chain->GDALTransformer = GDALTransformer;
195+
chain->GDALTransformerArg = GDALTransformerArg;
196+
memcpy(chain->adfGeotransform, padfGeotransform, sizeof(double)*6);
197+
// TODO: In reality we don't require the full homogeneous matrix, so GeoToPixelTransform and matrix inversion could
198+
// be optimized for simple scale+offset if there's the need (e.g. for numerical or performance reasons).
199+
if (!GDALInvGeoTransform(chain->adfGeotransform, chain->adfInvGeotransform))
143200
{
144-
double xT = x[i], yT = y[i];
145-
if ( bDstToSrc == FALSE )
146-
{
147-
x[i] = x0 + a * xT - b * yT;
148-
y[i] = y0 + b * xT + a * yT;
149-
}
150-
else
151-
{
152-
x[i] = ( a * ( xT - x0 ) + b * ( yT - y0 ) ) * 1 / ( pow( a, 2 ) + pow( b, 2 ) );
153-
y[i] = ( -b * ( xT - x0 ) + a * ( yT - y0 ) ) * 1 / ( pow( a, 2 ) + pow( b, 2 ) );
154-
}
155-
panSuccess[i] = TRUE;
201+
// Error handling if inversion fails - although the inverse transform is not needed for warp operation
202+
return NULL;
156203
}
157-
return TRUE;
204+
return (void*)chain;
158205
}
159206

160-
bool QgsImageWarper::warpgcp( const QString& input, const QString& output,
161-
const char *worldExt,
162-
std::vector<QgsPoint> mapCoords,
163-
std::vector<QgsPoint> pixelCoords,
164-
const int nReqOrder, ResamplingMethod resampling,
165-
bool useZeroAsTrans, const QString& compression, bool bUseTPS )
207+
void QgsImageWarper::destroyGeoToPixelTransform(void *GeoToPixelTransfomArg) const
166208
{
167-
int n = mapCoords.size();
168-
if (( nReqOrder == 1 && n < 3 ) || ( nReqOrder == 2 && n < 6 ) ||
169-
( nReqOrder == 3 && n < 10 ) ) return false;
170-
171-
CPLErr eErr;
172-
GDALDatasetH hSrcDS;
173-
GDALWarpOptions *psWarpOptions;
174-
openSrcDSAndGetWarpOpt( input, output, resampling,
175-
bUseTPS ? *GDALTPSTransform : *GDALGCPTransform,
176-
hSrcDS, psWarpOptions );
177-
178-
GDAL_GCP *pasGCPList = ( GDAL_GCP * ) malloc( n * sizeof( GDAL_GCP ) );
209+
delete static_cast<TransformChain *>(GeoToPixelTransfomArg);
210+
}
179211

180-
for ( int i = 0; i < n; i++ )
212+
int QgsImageWarper::GeoToPixelTransform( void *pTransformerArg, int bDstToSrc, int nPointCount,
213+
double *x, double *y, double *z, int *panSuccess )
214+
{
215+
TransformChain *chain = static_cast<TransformChain*>(pTransformerArg);
216+
if (chain == NULL)
181217
{
182-
pasGCPList[i].pszId = ( char * ) malloc( 20 * sizeof( char ) );
183-
sprintf( pasGCPList[i].pszId, "gcp%i", i );
184-
pasGCPList[i].pszInfo = NULL;
185-
pasGCPList[i].dfGCPPixel = pixelCoords[i].x();
186-
pasGCPList[i].dfGCPLine = - pixelCoords[i].y();
187-
pasGCPList[i].dfGCPX = mapCoords[i].x();
188-
pasGCPList[i].dfGCPY = mapCoords[i].y();
189-
pasGCPList[i].dfGCPZ = 0;
218+
return FALSE;
190219
}
191220

192-
GDALDriverH hDriver = GDALGetDriverByName( "GTiff" );
193-
GDALDatasetH hSrcCopyDS = GDALCreateCopy( hDriver, ".tmpcopy.tif", hSrcDS,
194-
TRUE, NULL, NULL, NULL );
195-
if ( hSrcCopyDS == NULL ) return false;
196-
197-
GDALSetGCPs( hSrcCopyDS, n, pasGCPList, "" );
198-
199-
if ( bUseTPS )
200-
psWarpOptions->pTransformerArg = GDALCreateTPSTransformer( n, pasGCPList, false );
201-
else
202-
psWarpOptions->pTransformerArg = GDALCreateGCPTransformer( n, pasGCPList, nReqOrder, false );
203-
204-
if ( psWarpOptions->pTransformerArg == NULL ) return false;
205-
206-
// create and warp the output file
207-
char **papszOptions = NULL;
208-
papszOptions = CSLSetNameValue( papszOptions, "INIT_DEST", "NO_DATA" );
209-
papszOptions = CSLSetNameValue( papszOptions, "COMPRESS", compression.toAscii() );
210-
eErr = GDALCreateAndReprojectImage( hSrcCopyDS,
211-
/*pszSrcWKT*/"", QFile::encodeName( output ).constData(), /*pszDstWKT*/"",
212-
hDriver, papszOptions, GDALResampleAlg( resampling ), 0.0, 0, NULL, NULL, psWarpOptions );
213-
if ( eErr != CE_None ) return false;
214-
215-
// write worldfile
216-
int nPixels, nLines;
217-
double adfGeoTransform[6];
218-
219-
eErr = GDALSuggestedWarpOutput( hSrcDS, GDALGCPTransform,
220-
psWarpOptions->pTransformerArg,
221-
adfGeoTransform, &nPixels, &nLines );
222-
if ( eErr != CE_None ) return false;
223-
224-
GDALWriteWorldFile( QFile::encodeName( output ).constData(), worldExt, adfGeoTransform );
225-
226-
free( pasGCPList );
227-
if ( bUseTPS )
228-
GDALDestroyTPSTransformer( psWarpOptions->pTransformerArg );
221+
if ( bDstToSrc == FALSE )
222+
{
223+
// Transform to georeferenced coordinates
224+
if (!chain->GDALTransformer(chain->GDALTransformerArg, bDstToSrc, nPointCount, x, y, z, panSuccess))
225+
{
226+
return FALSE;
227+
}
228+
// Transform from georeferenced to pixel/line
229+
for (int i = 0; i < nPointCount; ++i)
230+
{
231+
if (!panSuccess[i]) continue;
232+
double xP = x[i];
233+
double yP = y[i];
234+
x[i] = chain->adfInvGeotransform[0] + xP*chain->adfInvGeotransform[1] + yP*chain->adfInvGeotransform[2];
235+
y[i] = chain->adfInvGeotransform[3] + xP*chain->adfInvGeotransform[4] + yP*chain->adfInvGeotransform[5];
236+
}
237+
}
229238
else
230-
GDALDestroyGCPTransformer( psWarpOptions->pTransformerArg );
231-
GDALDestroyWarpOptions( psWarpOptions );
232-
GDALClose( hSrcDS );
239+
{
240+
// Transform from pixel/line to georeferenced coordinates
241+
for (int i = 0; i < nPointCount; ++i)
242+
{
243+
double P = x[i];
244+
double L = y[i];
245+
x[i] = chain->adfGeotransform[0] + P*chain->adfGeotransform[1] + L*chain->adfGeotransform[2];
246+
y[i] = chain->adfGeotransform[3] + P*chain->adfGeotransform[4] + L*chain->adfGeotransform[5];
247+
}
248+
// Transform from georeferenced coordinates to source pixel/line
249+
if (!chain->GDALTransformer(chain->GDALTransformerArg, bDstToSrc, nPointCount, x, y, z, panSuccess))
250+
{
251+
return FALSE;
252+
}
253+
}
254+
return TRUE;
255+
}
233256

234-
return true;
257+
void *QgsImageWarper::createWarpProgressArg(QProgressDialog *progressDialog) const
258+
{
259+
return (void *)progressDialog;
235260
}
236261

262+
int CPL_STDCALL QgsImageWarper::updateWarpProgress(double dfComplete, const char *pszMessage, void *pProgressArg)
263+
{
264+
QProgressDialog *progress = static_cast<QProgressDialog*>(pProgressArg);
265+
progress->setValue(std::min(100u, (uint)(dfComplete*100.0)));
266+
// TODO: call QEventLoop manually to make "cancel" button more responsive
267+
if (progress->wasCanceled())
268+
{
269+
//TODO: delete resulting file?
270+
return FALSE;
271+
}
272+
return TRUE;
273+
}

‎src/plugins/georeferencer/qgsimagewarper.h

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,53 +22,60 @@
2222
#include <vector>
2323
#include "qgspoint.h"
2424

25+
class QgsGeorefTransform;
26+
class QProgressDialog;
27+
class QWidget;
28+
2529
class QgsImageWarper
2630
{
2731
public:
32+
QgsImageWarper(QWidget *theParent);
2833

2934
enum ResamplingMethod
3035
{
3136
NearestNeighbour = GRA_NearestNeighbour,
32-
Bilinear = GRA_Bilinear,
33-
Cubic = GRA_Cubic,
37+
Bilinear = GRA_Bilinear,
38+
Cubic = GRA_Cubic,
39+
CubicSpline = GRA_CubicSpline,
40+
Lanczos = GRA_Lanczos
3441
};
3542

36-
37-
QgsImageWarper() { };
38-
QgsImageWarper( double angle ) : mAngle( angle ) { };
39-
40-
void warp( const QString& input, const QString& output,
41-
double& xOffset, double& yOffset,
42-
ResamplingMethod resampling = Bilinear,
43-
bool useZeroAsTrans = true,
44-
const QString& compression = "NONE" );
45-
46-
bool warpgcp( const QString& input, const QString& output,
47-
const char *worldExt,
48-
std::vector<QgsPoint> mapCoords,
49-
std::vector<QgsPoint> pixelCoords,
50-
const int nReqOrder = 1, ResamplingMethod resampling = Bilinear,
51-
bool useZeroAsTrans = true, const QString& compression = "NONE",
52-
bool bUseTPS = false );
53-
43+
bool warpFile( const QString& input, const QString& output, const QgsGeorefTransform &georefTransform,
44+
ResamplingMethod resampling = Bilinear, bool useZeroAsTrans = true, const QString& compression = "NONE");
5445
private:
55-
56-
struct TransformParameters
57-
{
58-
double angle;
59-
double x0;
60-
double y0;
46+
struct TransformChain {
47+
GDALTransformerFunc GDALTransformer;
48+
void * GDALTransformerArg;
49+
double adfGeotransform[6];
50+
double adfInvGeotransform[6];
6151
};
6252

63-
bool openSrcDSAndGetWarpOpt( const QString &input, const QString &output,
64-
const ResamplingMethod &resampling, const GDALTransformerFunc &pfnTransform,
65-
GDALDatasetH &hSrcDS, GDALWarpOptions *&psWarpOptions );
66-
67-
static int transform( void *pTransformerArg, int bDstToSrc, int nPointCount,
68-
double *x, double *y, double *z, int *panSuccess );
69-
70-
double mAngle;
71-
53+
//! \sa addGeoToPixelTransform
54+
static int GeoToPixelTransform( void *pTransformerArg, int bDstToSrc, int nPointCount,
55+
double *x, double *y, double *z, int *panSuccess );
56+
57+
/**
58+
* \brief Appends a transform from geocoordinates to pixel/line coordinates to the given GDAL transformer.
59+
*
60+
* The resulting transform is the functional composition of the given GDAL transformer and the
61+
* inverse geo transform.
62+
* \sa destroyGeoToPixelTransform
63+
* \returns Argument to use with the static GDAL callback \ref GeoToPixelTransform
64+
*/
65+
void *addGeoToPixelTransform(GDALTransformerFunc GDALTransformer, void *GDALTransformerArg, double *padfGeotransform) const;
66+
void destroyGeoToPixelTransform(void *GeoToPixelTransfomArg) const;
67+
68+
bool openSrcDSAndGetWarpOpt(const QString &input, const QString &output,
69+
const ResamplingMethod &resampling, const GDALTransformerFunc &pfnTransform,
70+
GDALDatasetH &hSrcDS, GDALWarpOptions *&psWarpOptions);
71+
72+
bool createDestinationDataset(const QString &outputName, GDALDatasetH hSrcDS, GDALDatasetH &hDstDS, uint resX, uint resY,
73+
double *adfGeoTransform, bool useZeroAsTrans, const QString& compression);
74+
75+
QWidget *mParent;
76+
void *createWarpProgressArg(QProgressDialog *progressDialog) const;
77+
//! \brief GDAL progress callback, used to display warping progress via a QProgressDialog
78+
static int CPL_STDCALL updateWarpProgress(double dfComplete, const char *pszMessage, void *pProgressArg);
7279
};
7380

7481

‎src/plugins/georeferencer/qgspointdialog.cpp

Lines changed: 370 additions & 270 deletions
Large diffs are not rendered by default.

‎src/plugins/georeferencer/qgspointdialog.h

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include <qgsmapcanvas.h>
2121
#include <qgsrasterlayer.h>
2222

23+
#include "qgsgeoreftransform.h"
24+
#include "qgsgcplist.h"
25+
2326
#include <ui_qgspointdialogbase.h>
2427

2528
class QAction;
@@ -28,6 +31,8 @@ class QIcon;
2831
class QgsGeorefDataPoint;
2932
class QgsMapTool;
3033
class QgisInterface;
34+
class QgsGCPListWidget;
35+
3136

3237
class QgsPointDialog : public QDialog, private Ui::QgsPointDialogBase
3338
{
@@ -46,7 +51,6 @@ class QgsPointDialog : public QDialog, private Ui::QgsPointDialogBase
4651
static QWidget* findMainWindow();
4752

4853
public slots:
49-
5054
void addPoint( const QgsPoint& pixelCoords, const QgsPoint& mapCoords );
5155
void on_pbnClose_clicked();
5256
void on_pbnSelectRaster_clicked();
@@ -56,29 +60,52 @@ class QgsPointDialog : public QDialog, private Ui::QgsPointDialogBase
5660
void on_pbnSelectModifiedRaster_clicked();
5761
void on_pbnSaveGCPs_clicked();
5862
void on_pbnLoadGCPs_clicked();
63+
void on_pbnShowGCPList_clicked();
5964
void on_cmbTransformType_currentIndexChanged( const QString& );
6065
void on_leSelectModifiedRaster_textChanged( const QString & );
66+
6167
void zoomIn();
6268
void zoomOut();
6369
void zoomToLayer();
6470
void pan();
6571
void addPoint();
6672
void deletePoint();
73+
74+
void onLinkQgisToGeorefChanged( int ); // Called when the checkbox state changes
75+
void onLinkGeorefToQgisChanged( int ); // Called when the checkbox state changes
76+
void extentsChangedGeorefCanvas(); // Called when the georef canvas extents have changed. Used by map follow mode.
77+
void extentsChangedMainCanvas(); // Called when the qgis main canvas extents have changed. Used by map follow mode.
78+
79+
void jumpToGCP(uint theGCPIndex);
80+
//
6781
// void enableRelevantControls( void );
6882

6983
private:
70-
7184
void initialize();
7285
bool generateWorldFileAndWarp();
7386
bool helmertWarp();
7487
void loadGCPs( QString & );
7588
void saveGCPs( std::vector<QgsPoint>, std::vector<QgsPoint> );
89+
void addPointWithoutRefresh( const QgsPoint& pixelCoords, const QgsPoint& mapCoords );
90+
7691
QString guessWorldFileName( const QString& raster );
7792

7893
void enableModifiedRasterControls( bool state );
7994
void enableControls( bool state );
8095
QIcon getThemeIcon( const QString theName );
8196

97+
// The transformer used to align the qgis main canvas and the georeferencer canvas (and/or vice versa)
98+
QgsGeorefTransform mGeorefTransform;
99+
bool mGCPsDirty; // GCPs changed since last transform update
100+
101+
bool mExtentsChangedRecursionGuard;
102+
103+
void createGCPVectors(std::vector<QgsPoint> &mapCoords, std::vector<QgsPoint> &pixelCoords) const;
104+
bool updateGeorefTransform();
105+
106+
// Converts the given transform name to enum
107+
QgsGeorefTransform::TransformParametrisation convertTransformStringToEnum(const QString &transformName) const throw (std::invalid_argument);
108+
82109
QActionGroup* mMapToolGroup;
83110
QAction* mActionZoomIn;
84111
QAction* mActionZoomOut;
@@ -106,9 +133,12 @@ class QgsPointDialog : public QDialog, private Ui::QgsPointDialogBase
106133

107134
// std::vector<QgsPoint> mPixelCoords, mMapCoords;
108135
// std::vector<QString> mAcetateIDs;
109-
std::vector<QgsGeorefDataPoint*> mPoints;
136+
//std::vector<QgsGeorefDataPoint*>
137+
QgsGCPList mPoints;
110138
QgisInterface* mIface;
111139
int mAcetateCounter;
140+
141+
QgsGCPListWidget *mGCPListWidget;
112142
};
113143

114144
#endif

‎src/plugins/georeferencer/qgspointdialogbase.ui

Lines changed: 193 additions & 168 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.