mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-15 00:07:25 -05:00
Add argument to QgsCoordinateTransform::transformBoundingBox to flag that
handling of a bounding box which crosses the 180 degree longitude line is required. Fix composer map reprojected grids which cross 180 degree line.
This commit is contained in:
parent
d66e4dc175
commit
a2d5acb516
@ -114,9 +114,11 @@ class QgsCoordinateTransform : QObject
|
||||
* returned rectangle.
|
||||
* @param theRect rect to transform
|
||||
* @param direction TransformDirection (defaults to ForwardTransform)
|
||||
* @param handle180Crossover set to true if destination crs is geographic and handling of extents crossing the 180 degree
|
||||
* longitude line is required
|
||||
* @return QgsRectangle in Destination Coordinate System
|
||||
*/
|
||||
QgsRectangle transformBoundingBox( const QgsRectangle theRect, TransformDirection direction = ForwardTransform ) const throw (QgsCsException);
|
||||
QgsRectangle transformBoundingBox( const QgsRectangle theRect, TransformDirection direction = ForwardTransform, const bool handle180Crossover = false ) const throw (QgsCsException);
|
||||
|
||||
// Same as for the other transform() functions, but alters the x
|
||||
// and y variables in place. The second one works with good old-fashioned
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgssymbollayerv2utils.h"
|
||||
#include "qgssymbolv2.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
@ -1356,6 +1357,15 @@ int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const
|
||||
double maxX = bbox.xMaximum();
|
||||
double step = ( maxX - minX ) / 20;
|
||||
|
||||
bool crosses180 = false;
|
||||
bool crossed180 = false;
|
||||
if ( mCRS.geographicFlag() && ( minX > maxX ) )
|
||||
{
|
||||
//handle 180 degree longitude crossover
|
||||
crosses180 = true;
|
||||
step = ( maxX + 360.0 - minX ) / 20;
|
||||
}
|
||||
|
||||
int gridLineCount = 0;
|
||||
while ( currentLevel >= bbox.yMinimum() && gridLineCount < MAX_GRID_LINES )
|
||||
{
|
||||
@ -1364,7 +1374,7 @@ int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const
|
||||
bool cont = true;
|
||||
while ( cont )
|
||||
{
|
||||
if ( currentX > maxX )
|
||||
if (( !crosses180 || crossed180 ) && ( currentX > maxX ) )
|
||||
{
|
||||
cont = false;
|
||||
}
|
||||
@ -1372,7 +1382,13 @@ int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const
|
||||
QgsPoint mapPoint = t.transform( currentX, currentLevel ); //transform back to map crs
|
||||
gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) ); //transform back to composer coords
|
||||
currentX += step;
|
||||
if ( crosses180 && currentX > 180.0 )
|
||||
{
|
||||
currentX -= 360.0;
|
||||
crossed180 = true;
|
||||
}
|
||||
}
|
||||
crossed180 = false;
|
||||
|
||||
gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
|
||||
if ( gridLine.size() > 0 )
|
||||
@ -1401,8 +1417,16 @@ int QgsComposerMapGrid::yGridLinesCRSTransform( const QgsRectangle& bbox, const
|
||||
double maxY = bbox.yMaximum();
|
||||
double step = ( maxY - minY ) / 20;
|
||||
|
||||
bool crosses180 = false;
|
||||
bool crossed180 = false;
|
||||
if ( mCRS.geographicFlag() && ( bbox.xMinimum() > bbox.xMaximum() ) )
|
||||
{
|
||||
//handle 180 degree longitude crossover
|
||||
crosses180 = true;
|
||||
}
|
||||
|
||||
int gridLineCount = 0;
|
||||
while ( currentLevel <= bbox.xMaximum() && gridLineCount < MAX_GRID_LINES )
|
||||
while (( currentLevel <= bbox.xMaximum() || ( crosses180 && !crossed180 ) ) && gridLineCount < MAX_GRID_LINES )
|
||||
{
|
||||
QPolygonF gridLine;
|
||||
double currentY = minY;
|
||||
@ -1427,6 +1451,11 @@ int QgsComposerMapGrid::yGridLinesCRSTransform( const QgsRectangle& bbox, const
|
||||
gridLineCount++;
|
||||
}
|
||||
currentLevel += mGridIntervalX;
|
||||
if ( crosses180 && currentLevel > 180.0 )
|
||||
{
|
||||
currentLevel -= 360.0;
|
||||
crossed180 = true;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1735,7 +1764,33 @@ int QgsComposerMapGrid::crsGridParams( QgsRectangle& crsRect, QgsCoordinateTrans
|
||||
QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
|
||||
QRectF mbr = mapPolygon.boundingRect();
|
||||
QgsRectangle mapBoundingRect( mbr.left(), mbr.bottom(), mbr.right(), mbr.top() );
|
||||
crsRect = tr.transformBoundingBox( mapBoundingRect );
|
||||
|
||||
|
||||
if ( mCRS.geographicFlag() )
|
||||
{
|
||||
//handle crossing the 180 degree longitude line
|
||||
QgsPoint lowerLeft( mapBoundingRect.xMinimum(), mapBoundingRect.yMinimum() );
|
||||
QgsPoint upperRight( mapBoundingRect.xMaximum(), mapBoundingRect.yMaximum() );
|
||||
|
||||
lowerLeft = tr.transform( lowerLeft.x(), lowerLeft.y() );
|
||||
upperRight = tr.transform( upperRight.x(), upperRight.y() );
|
||||
|
||||
if ( lowerLeft.x() > upperRight.x() )
|
||||
{
|
||||
//we've crossed the line
|
||||
crsRect = tr.transformBoundingBox( mapBoundingRect, QgsCoordinateTransform::ForwardTransform, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
//didn't cross the line
|
||||
crsRect = tr.transformBoundingBox( mapBoundingRect );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
crsRect = tr.transformBoundingBox( mapBoundingRect );
|
||||
}
|
||||
|
||||
inverseTransform.setSourceCrs( mCRS );
|
||||
inverseTransform.setDestCRS( mComposerMap->composition()->mapSettings().destinationCrs() );
|
||||
return 0;
|
||||
|
||||
@ -520,7 +520,7 @@ void QgsCoordinateTransform::transformInPlace(
|
||||
#endif //ANDROID
|
||||
|
||||
|
||||
QgsRectangle QgsCoordinateTransform::transformBoundingBox( const QgsRectangle rect, TransformDirection direction ) const
|
||||
QgsRectangle QgsCoordinateTransform::transformBoundingBox( const QgsRectangle rect, TransformDirection direction, const bool handle180Crossover ) const
|
||||
{
|
||||
// Calculate the bounding box of a QgsRectangle in the source CRS
|
||||
// when projected to the destination CRS (or the inverse).
|
||||
@ -592,8 +592,29 @@ QgsRectangle QgsCoordinateTransform::transformBoundingBox( const QgsRectangle re
|
||||
|
||||
for ( int i = 0; i < numP * numP; i++ )
|
||||
{
|
||||
if ( qIsFinite( x[i] ) && qIsFinite( y[i] ) )
|
||||
if ( !qIsFinite( x[i] ) || !qIsFinite( y[i] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( handle180Crossover )
|
||||
{
|
||||
//if crossing the date line, temporarily add 360 degrees to -ve longitudes
|
||||
bb_rect.combineExtentWith( x[i] >= 0.0 ? x[i] : x[i] + 360.0, y[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
bb_rect.combineExtentWith( x[i], y[i] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( handle180Crossover )
|
||||
{
|
||||
//subtract temporary addition of 360 degrees from longitudes
|
||||
if ( bb_rect.xMinimum() > 180.0 )
|
||||
bb_rect.setXMinimum( bb_rect.xMinimum() - 360.0 );
|
||||
if ( bb_rect.xMaximum() > 180.0 )
|
||||
bb_rect.setXMaximum( bb_rect.xMaximum() - 360.0 );
|
||||
}
|
||||
|
||||
QgsDebugMsg( "Projected extent: " + bb_rect.toString() );
|
||||
|
||||
@ -148,9 +148,11 @@ class CORE_EXPORT QgsCoordinateTransform : public QObject
|
||||
* returned rectangle.
|
||||
* @param theRect rect to transform
|
||||
* @param direction TransformDirection (defaults to ForwardTransform)
|
||||
* @param handle180Crossover set to true if destination crs is geographic and handling of extents crossing the 180 degree
|
||||
* longitude line is required
|
||||
* @return QgsRectangle in Destination Coordinate System
|
||||
*/
|
||||
QgsRectangle transformBoundingBox( const QgsRectangle theRect, TransformDirection direction = ForwardTransform ) const;
|
||||
QgsRectangle transformBoundingBox( const QgsRectangle theRect, TransformDirection direction = ForwardTransform, const bool handle180Crossover = false ) const;
|
||||
|
||||
// Same as for the other transform() functions, but alters the x
|
||||
// and y variables in place. The second one works with good old-fashioned
|
||||
|
||||
@ -98,6 +98,7 @@ ADD_QGIS_TEST(blendmodestest testqgsblendmodes.cpp)
|
||||
ADD_QGIS_TEST(geometrytest testqgsgeometry.cpp)
|
||||
ADD_QGIS_TEST(geometryimporttest testqgsgeometryimport.cpp)
|
||||
ADD_QGIS_TEST(coordinatereferencesystemtest testqgscoordinatereferencesystem.cpp)
|
||||
ADD_QGIS_TEST(coordinatetransformtest testqgscoordinatetransform.cpp)
|
||||
ADD_DEPENDENCIES(qgis_coordinatereferencesystemtest synccrsdb)
|
||||
ADD_QGIS_TEST(pointtest testqgspoint.cpp)
|
||||
ADD_QGIS_TEST(vectordataprovidertest testqgsvectordataprovider.cpp)
|
||||
|
||||
65
tests/src/core/testqgscoordinatetransform.cpp
Normal file
65
tests/src/core/testqgscoordinatetransform.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/***************************************************************************
|
||||
testqgscoordinatetransform.cpp
|
||||
-----------------------
|
||||
begin : October 2014
|
||||
copyright : (C) 2014 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include "qgscoordinatetransform.h"
|
||||
#include "qgsapplication.h"
|
||||
#include <QObject>
|
||||
#include <QtTest>
|
||||
|
||||
class TestQgsCoordinateTransform: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void transformBoundingBox();
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
void TestQgsCoordinateTransform::initTestCase()
|
||||
{
|
||||
QgsApplication::init();
|
||||
QgsApplication::initQgis();
|
||||
|
||||
}
|
||||
|
||||
void TestQgsCoordinateTransform::transformBoundingBox()
|
||||
{
|
||||
//test transforming a bounding box which crosses the 180 degree longitude line
|
||||
QgsCoordinateReferenceSystem sourceSrs;
|
||||
sourceSrs.createFromSrid( 3994 );
|
||||
QgsCoordinateReferenceSystem destSrs;
|
||||
destSrs.createFromSrid( 4326 );
|
||||
|
||||
QgsCoordinateTransform tr( sourceSrs, destSrs );
|
||||
QgsRectangle crossingRect( 6374985, -3626584, 7021195, -3272435 );
|
||||
QgsRectangle resultRect = tr.transformBoundingBox( crossingRect, QgsCoordinateTransform::ForwardTransform, true );
|
||||
QgsRectangle expectedRect;
|
||||
expectedRect.setXMinimum( 175.771 );
|
||||
expectedRect.setYMinimum( -39.7222 );
|
||||
expectedRect.setXMaximum( -176.549 );
|
||||
expectedRect.setYMaximum( -36.3951 );
|
||||
QVERIFY( qgsDoubleNear( resultRect.xMinimum(), expectedRect.xMinimum(), 0.001 ) );
|
||||
QVERIFY( qgsDoubleNear( resultRect.yMinimum(), expectedRect.yMinimum(), 0.001 ) );
|
||||
QVERIFY( qgsDoubleNear( resultRect.xMaximum(), expectedRect.xMaximum(), 0.001 ) );
|
||||
QVERIFY( qgsDoubleNear( resultRect.yMaximum(), expectedRect.yMaximum(), 0.001 ) );
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsCoordinateTransform )
|
||||
#include "moc_testqgscoordinatetransform.cxx"
|
||||
Loading…
x
Reference in New Issue
Block a user