1
/***************************************************************************
2
QgsCoordinateTransform.cpp - Coordinate Transforms
5
copyright : (C) 2004 Tim Sutton
6
email : tim at linfiniti.com
7
***************************************************************************/
9
/***************************************************************************
11
* This program is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
16
***************************************************************************/
17
/* $Id: qgscoordinatetransform.cpp,v 1.42.2.16 2005/09/21 22:51:25 timlinux Exp $ */
19
#include "qgscoordinatetransform.h"
24
QgsCoordinateTransform::QgsCoordinateTransform( ) : QObject()
29
QgsCoordinateTransform::QgsCoordinateTransform(const QgsSpatialRefSys& source,
30
const QgsSpatialRefSys& dest)
38
QgsCoordinateTransform::QgsCoordinateTransform( QString theSourceSRS, QString theDestSRS ) : QObject()
41
mSourceSRS.createFromWkt(theSourceSRS);
42
mDestSRS.createFromWkt(theDestSRS);
43
// initialize the coordinate system data structures
44
//XXX Who spells initialize initialise?
45
//XXX A: Its the queen's english....
46
//XXX : Long live the queen! Lets get on with the initialisation...
50
QgsCoordinateTransform::QgsCoordinateTransform(long theSourceSrid,
52
QgsSpatialRefSys::SRS_TYPE theSourceSRSType): QObject()
55
mSourceSRS.createFromId(theSourceSrid, theSourceSRSType);
56
mDestSRS.createFromWkt(theDestWKT);
57
// initialize the coordinate system data structures
58
//XXX Who spells initialize initialise?
59
//XXX A: Its the queen's english....
60
//XXX : Long live the queen! Lets get on with the initialisation...
64
QgsCoordinateTransform::~QgsCoordinateTransform()
66
// free the proj objects
67
if (mSourceProjection)
69
pj_free(mSourceProjection);
71
if (mDestinationProjection)
73
pj_free(mDestinationProjection);
77
void QgsCoordinateTransform::setSourceSRS(const QgsSpatialRefSys& theSRS)
82
void QgsCoordinateTransform::setDestSRS(const QgsSpatialRefSys& theSRS)
85
std::cout << "QgsCoordinateTransform::setDestSRS called" << std::endl;
92
void QgsCoordinateTransform::setDestSRSID (long theSRSID)
94
//!todo Add some logic here to determine if the srsid is a system or user one
96
std::cout << "QgsCoordinateTransform::setDestSRSID slot called" << std::endl;
98
mDestSRS.createFromSrsId(theSRSID);
102
// XXX This whole function is full of multiple return statements!!!
103
void QgsCoordinateTransform::initialise()
106
mInitialisedFlag=false; //guilty until proven innocent...
107
mSourceProjection = NULL;
108
mDestinationProjection = NULL;
110
// XXX Warning - multiple return paths in this block!!
111
if (!mSourceSRS.isValid())
113
//mSourceSRS = defaultWkt;
114
// Pass through with no projection since we have no idea what the layer
115
// coordinates are and projecting them may not be appropriate
116
mShortCircuit = true;
120
if (!mDestSRS.isValid())
122
//No destination projection is set so we set the default output projection to
123
//be the same as input proj. This only happens on the first layer loaded
124
//whatever that may be...
125
mDestSRS.createFromProj4(mSourceSRS.proj4String());
128
//XXX todo overload == operator for QgsSpatialRefSys
129
//at the moment srs.parameters contains the whole proj def...soon it wont...
130
//if (mSourceSRS->proj4String() == mDestSRS->proj4String())
131
if (mSourceSRS == mDestSRS)
133
// If the source and destination projection are the same, set the short
134
// circuit flag (no transform takes place)
140
// Transform must take place
144
// init the projections (destination and source)
145
mDestinationProjection = pj_init_plus(mDestSRS.proj4String().local8Bit());
146
mSourceProjection = pj_init_plus(mSourceSRS.proj4String().local8Bit());
148
mInitialisedFlag = true;
149
if ( mDestinationProjection == NULL )
151
mInitialisedFlag = false;
153
if ( mSourceProjection == NULL )
155
mInitialisedFlag = false;
158
if (mInitialisedFlag)
161
std::cout << "------------------------------------------------------------"<< std::endl;
162
std::cout << "QgsCoordinateTransform::initialise()" << std::endl;
163
std::cout << "The OGR Coordinate transformation for this layer was set to" << std::endl;
164
// note overloaded << operator on qgsspatialrefsys cant be used on pointers -
165
// so we dereference them like this (*mSourceSRS) (Thanks Lars for pointing that out)
166
std::cout << "INPUT: " << std::endl << mSourceSRS << std::endl;
167
std::cout << "OUTPUT: " << std::endl << mDestSRS << std::endl;
168
std::cout << "------------------------------------------------------------" << std::endl;
172
std::cout << "------------------------------------------------------------"<< std::endl;
173
std::cout << "QgsCoordinateTransform::initialise()" << std::endl;
174
std::cout << "The OGR Coordinate transformation FAILED TO INITIALISE!" << std::endl;
175
std::cout << "------------------------------------------------------------"<< std::endl;
181
// TRANSFORMERS BELOW THIS POINT .........
187
QgsPoint QgsCoordinateTransform::transform(const QgsPoint thePoint,TransformDirection direction)
189
if (mShortCircuit || !mInitialisedFlag) return thePoint;
191
double x = thePoint.x();
192
double y = thePoint.y();
196
transformCoords(1, &x, &y, &z, direction );
198
catch(QgsCsException &cse)
200
// rethrow the exception
201
std::cout << "Throwing exception " << __FILE__ << __LINE__ << std::endl;
206
//std::cout << "Point projection...X : " << thePoint.x() << "-->" << x << ", Y: " << thePoint.y() << " -->" << y << std::endl;
208
return QgsPoint(x, y);
212
QgsPoint QgsCoordinateTransform::transform(const double theX, const double theY=0,TransformDirection direction)
216
return transform(QgsPoint(theX, theY), direction);
218
catch(QgsCsException &cse)
220
// rethrow the exception
221
std::cout << "Throwing exception " << __FILE__ << __LINE__ << std::endl;
226
QgsRect QgsCoordinateTransform::transform(const QgsRect theRect,TransformDirection direction)
228
if (mShortCircuit || !mInitialisedFlag) return theRect;
230
double x1 = theRect.xMin();
231
double y1 = theRect.yMin();
232
double x2 = theRect.xMax();
233
double y2 = theRect.yMax();
238
// Number of points to reproject------+
244
transformCoords(1, &x1, &y1, &z, direction);
245
transformCoords(1, &x2, &y2, &z, direction);
247
catch(QgsCsException &cse)
249
// rethrow the exception
250
std::cout << "Throwing exception " << __FILE__ << __LINE__ << std::endl;
255
std::cout << "Rect projection..."
270
return QgsRect(x1, y1, x2 , y2);
273
void QgsCoordinateTransform::transformInPlace(double& x, double& y, double& z,
274
TransformDirection direction)
276
if (mShortCircuit || !mInitialisedFlag)
279
//std::cout << "Using transform in place " << __FILE__ << " " << __LINE__ << std::endl;
284
transformCoords(1, &x, &y, &z, direction );
286
catch(QgsCsException &cse)
288
// rethrow the exception
289
std::cout << "Throwing exception " << __FILE__ << __LINE__ << std::endl;
294
void QgsCoordinateTransform::transformInPlace(std::vector<double>& x,
295
std::vector<double>& y, std::vector<double>& z,
296
TransformDirection direction)
298
if (mShortCircuit || !mInitialisedFlag)
301
assert(x.size() == y.size());
303
// Apparently, if one has a std::vector, it is valid to use the
304
// address of the first element in the vector as a pointer to an
305
// array of the vectors data, and hence easily interface with code
306
// that wants C-style arrays.
310
transformCoords(x.size(), &x[0], &y[0], &z[0], direction);
312
catch(QgsCsException &cse)
314
// rethrow the exception
315
std::cout << "Throwing exception " << __FILE__ << __LINE__ << std::endl;
321
QgsRect QgsCoordinateTransform::transformBoundingBox(const QgsRect rect, TransformDirection direction)
323
// Calculate the bounding box of a QgsRect in the source SRS
324
// when projected to the destination SRS (or the inverse).
325
// This is done by looking at a number of points spread evenly
326
// across the rectangle
328
if (mShortCircuit || !mInitialisedFlag)
331
static const int numP = 8;
334
bb_rect.setMinimal();
336
// We're interfacing with C-style vectors in the
337
// end, so let's do C-style vectors here too.
339
double x[numP * numP];
340
double y[numP * numP];
341
double z[numP * numP];
343
std::cout << "Entering transformBoundingBox..." << std::endl;
345
// Populate the vectors
347
double dx = rect.width() / (double)(numP - 1);
348
double dy = rect.height() / (double)(numP - 1);
350
double pointY = rect.yMin();
352
for (int i = 0; i < numP ; i++)
355
// Start at right edge
356
double pointX = rect.xMin();
358
for (int j = 0; j < numP; j++)
360
x[(i*numP) + j] = pointX;
361
y[(i*numP) + j] = pointY;
363
z[(i*numP) + j] = 0.0;
364
// std::cout << "BBox coord: (" << x[(i*numP) + j] << ", " << y[(i*numP) + j]
365
// << ")" << std::endl;
371
// Do transformation. Any exception generated must
372
// be handled in above layers.
375
transformCoords(numP * numP, x, y, z, direction);
377
catch(QgsCsException &cse)
379
// rethrow the exception
380
std::cout << "Throwing exception " << __FILE__ << __LINE__ << std::endl;
384
// Calculate the bounding box and use that for the extent
386
for (int i = 0; i < numP * numP; i++)
388
bb_rect.combineExtentWith(x[i], y[i]);
391
std::cout << "Projected extent: " << (bb_rect.stringRep()).local8Bit() << std::endl;
396
void QgsCoordinateTransform::transformCoords( const int& numPoints, double *x, double *y, double *z,TransformDirection direction)
398
assert(mSourceSRS.isValid());
399
assert(mDestSRS.isValid());
403
//std::cout << "[[[[[[Number of points to transform: " << numPoints << "]]]]]]" << std::endl;
405
// use proj4 to do the transform
407
// if the source/destination projection is lat/long, convert the points to radians
408
// prior to transforming
409
if((pj_is_latlong(mDestinationProjection) && (direction == INVERSE))
410
|| (pj_is_latlong(mSourceProjection) && (direction == FORWARD)))
412
for (int i = 0; i < numPoints; ++i)
421
if(direction == INVERSE)
424
std::cout << "!!!! INVERSE PROJ4 TRANSFORM !!!!" << std::endl;
425
std::cout << " numPoint: " << numPoints << std::endl;
426
std::cout << " x : " << x << std::endl;
427
std::cout << " y : " << y << std::endl;
429
projResult = pj_transform(mDestinationProjection, mSourceProjection , numPoints, 0, x, y, z);
435
std::cout << "!!!! FORWARD PROJ4 TRANSFORM !!!!" << std::endl;
436
std::cout << " numPoint: " << numPoints << std::endl;
437
std::cout << " x : " << x << std::endl;
438
std::cout << " y : " << y << std::endl;
439
std::cout << " z : " << z << std::endl;
441
assert(mSourceProjection != 0);
442
assert(mDestinationProjection !=0);
443
projResult = pj_transform(mSourceProjection, mDestinationProjection, numPoints, 0, x, y, z);
449
//something bad happened....
451
QTextOStream pjErr(&msg);
453
pjErr << tr("Failed") << " " << dir << " " << tr("transform of") << '\n';
454
for (int i = 0; i < numPoints; ++i)
456
if(direction == FORWARD)
458
pjErr << "(" << x[i] << ", " << y[i] << ")\n";
462
pjErr << "(" << x[i] * RAD_TO_DEG << ", " << y[i] * RAD_TO_DEG << ")\n";
466
pjErr << tr("with error: ") << pj_strerrno(projResult) << '\n';
468
std::cout << "Projection failed emitting invalid transform signal: \n" << msg.local8Bit() << std::endl;
470
emit invalidTransformInput();
471
std::cout << "Throwing exception " << __FILE__ << __LINE__ << std::endl;
472
throw QgsCsException(msg);
474
// if the result is lat/long, convert the results from radians back
476
if((pj_is_latlong(mDestinationProjection) && (direction == FORWARD))
477
|| (pj_is_latlong(mSourceProjection) && (direction == INVERSE)))
479
for (int i = 0; i < numPoints; ++i)
487
// std::cout << "[[[[[[ Projected " << xorg << ", " << yorg << " to " << x << ", " << y << " ]]]]]]"<< std::endl;
491
bool QgsCoordinateTransform::readXML( QDomNode & theNode )
494
std::cout << "Reading Coordinate Transform from xml ------------------------!" << std::endl;
496
QDomNode mySrcNodeParent = theNode.namedItem("sourcesrs");
497
QDomNode mySrcNode = mySrcNodeParent.namedItem("spatialrefsys");
498
mSourceSRS.readXML(mySrcNode);
499
QDomNode myDestNodeParent = theNode.namedItem("destinationsrs");
500
QDomNode myDestNode = myDestNodeParent.namedItem("spatialrefsys");
501
mDestSRS.readXML(myDestNode);
508
bool QgsCoordinateTransform::writeXML( QDomNode & theNode, QDomDocument & theDoc )
511
QDomElement myNodeElement = theNode.toElement();
512
QDomElement myTransformElement = theDoc.createElement( "coordinatetransform" );
514
QDomElement mySourceElement = theDoc.createElement( "sourcesrs" );
515
mSourceSRS.writeXML(mySourceElement, theDoc);
516
myTransformElement.appendChild(mySourceElement);
518
QDomElement myDestElement = theDoc.createElement( "destinationsrs" );
519
mDestSRS.writeXML(myDestElement, theDoc);
520
myTransformElement.appendChild(myDestElement);
522
myNodeElement.appendChild(myTransformElement);