Skip to content

Commit 8aa0573

Browse files
authoredNov 30, 2017
Merge pull request #5768 from wonder-sk/fix-17514-crs-change
Fix 3D view if terrain DEM is in different CRS
2 parents ded892e + 997286f commit 8aa0573

21 files changed

+338
-51
lines changed
 

‎src/3d/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ SET(QGIS_3D_SRCS
1111
qgstessellatedpolygongeometry.cpp
1212
qgstessellator.cpp
1313
qgstilingscheme.cpp
14+
qgsvector3d.cpp
1415
qgsvectorlayer3drenderer.cpp
1516

1617
chunks/qgschunkboundsentity_p.cpp
@@ -84,6 +85,7 @@ SET(QGIS_3D_HDRS
8485
qgstessellatedpolygongeometry.h
8586
qgstessellator.h
8687
qgstilingscheme.h
88+
qgsvector3d.h
8789
qgsvectorlayer3drenderer.h
8890

8991
chunks/qgschunkboundsentity_p.h

‎src/3d/qgs3dmapsettings.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828

2929
Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
3030
: QObject()
31-
, mOriginX( other.mOriginX )
32-
, mOriginY( other.mOriginY )
33-
, mOriginZ( other.mOriginZ )
31+
, mOrigin( other.mOrigin )
3432
, mCrs( other.mCrs )
3533
, mBackgroundColor( other.mBackgroundColor )
3634
, mTerrainVerticalScale( other.mTerrainVerticalScale )
@@ -59,9 +57,10 @@ Qgs3DMapSettings::~Qgs3DMapSettings()
5957
void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
6058
{
6159
QDomElement elemOrigin = elem.firstChildElement( "origin" );
62-
mOriginX = elemOrigin.attribute( "x" ).toDouble();
63-
mOriginY = elemOrigin.attribute( "y" ).toDouble();
64-
mOriginZ = elemOrigin.attribute( "z" ).toDouble();
60+
mOrigin = QgsVector3D(
61+
elemOrigin.attribute( "x" ).toDouble(),
62+
elemOrigin.attribute( "y" ).toDouble(),
63+
elemOrigin.attribute( "z" ).toDouble() );
6564

6665
QDomElement elemCrs = elem.firstChildElement( "crs" );
6766
mCrs.readXml( elemCrs );
@@ -85,7 +84,9 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
8584
QString terrainGenType = elemTerrainGenerator.attribute( "type" );
8685
if ( terrainGenType == "dem" )
8786
{
88-
mTerrainGenerator.reset( new QgsDemTerrainGenerator );
87+
QgsDemTerrainGenerator *demTerrainGenerator = new QgsDemTerrainGenerator;
88+
demTerrainGenerator->setCrs( mCrs );
89+
mTerrainGenerator.reset( demTerrainGenerator );
8990
}
9091
else if ( terrainGenType == "quantized-mesh" )
9192
{
@@ -139,9 +140,9 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
139140
QDomElement elem = doc.createElement( "qgis3d" );
140141

141142
QDomElement elemOrigin = doc.createElement( "origin" );
142-
elemOrigin.setAttribute( "x", QString::number( mOriginX ) );
143-
elemOrigin.setAttribute( "y", QString::number( mOriginY ) );
144-
elemOrigin.setAttribute( "z", QString::number( mOriginZ ) );
143+
elemOrigin.setAttribute( "x", QString::number( mOrigin.x() ) );
144+
elemOrigin.setAttribute( "y", QString::number( mOrigin.y() ) );
145+
elemOrigin.setAttribute( "z", QString::number( mOrigin.z() ) );
145146
elem.appendChild( elemOrigin );
146147

147148
QDomElement elemCrs = doc.createElement( "crs" );
@@ -210,11 +211,14 @@ void Qgs3DMapSettings::resolveReferences( const QgsProject &project )
210211
}
211212
}
212213

213-
void Qgs3DMapSettings::setOrigin( double originX, double originY, double originZ )
214+
QgsVector3D Qgs3DMapSettings::mapToWorldCoordinates( const QgsVector3D &mapCoords ) const
214215
{
215-
mOriginX = originX;
216-
mOriginY = originY;
217-
mOriginZ = originZ;
216+
return Qgs3DUtils::mapToWorldCoordinates( mapCoords, mOrigin );
217+
}
218+
219+
QgsVector3D Qgs3DMapSettings::worldToMapCoordinates( const QgsVector3D &worldCoords ) const
220+
{
221+
return Qgs3DUtils::worldToMapCoordinates( worldCoords, mOrigin );
218222
}
219223

220224
void Qgs3DMapSettings::setCrs( const QgsCoordinateReferenceSystem &crs )

‎src/3d/qgs3dmapsettings.h

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "qgscoordinatereferencesystem.h"
2626
#include "qgsmaplayerref.h"
2727
#include "qgsterraingenerator.h"
28+
#include "qgsvector3d.h"
2829

2930
class QgsMapLayer;
3031
class QgsRasterLayer;
@@ -37,6 +38,7 @@ class QgsProject;
3738

3839
class QDomElement;
3940

41+
4042
/**
4143
* \ingroup 3d
4244
* Definition of the world
@@ -72,13 +74,14 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
7274
* Need to look into more advanced techniques like "relative to center" or "relative to eye"
7375
* to improve the precision.
7476
*/
75-
void setOrigin( double originX, double originY, double originZ );
76-
//! Returns X coordinate in map CRS at which 3D scene has origin (zero)
77-
double originX() const { return mOriginX; }
78-
//! Returns Y coordinate in map CRS at which 3D scene has origin (zero)
79-
double originY() const { return mOriginY; }
80-
//! Returns Z coordinate in map CRS at which 3D scene has origin (zero)
81-
double originZ() const { return mOriginZ; }
77+
void setOrigin( const QgsVector3D &origin ) { mOrigin = origin; }
78+
//! Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
79+
QgsVector3D origin() const { return mOrigin; }
80+
81+
//! Converts map coordinates to 3D world coordinates (applies offset and turns (x,y,z) into (x,-z,y))
82+
QgsVector3D mapToWorldCoordinates( const QgsVector3D &mapCoords ) const;
83+
//! Converts 3D world coordinates to map coordinates (applies offset and turns (x,y,z) into (x,-z,y))
84+
QgsVector3D worldToMapCoordinates( const QgsVector3D &worldCoords ) const;
8285

8386
//! Sets coordinate reference system used in the 3D scene
8487
void setCrs( const QgsCoordinateReferenceSystem &crs );
@@ -218,12 +221,8 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
218221
void showLabelsChanged();
219222

220223
private:
221-
//! X coordinate in map CRS at which our 3D world has origin (0,0,0)
222-
double mOriginX = 0;
223-
//! Y coordinate in map CRS at which our 3D world has origin (0,0,0)
224-
double mOriginY = 0;
225-
//! Z coordinate in map CRS at which our 3D world has origin (0,0,0)
226-
double mOriginZ = 0;
224+
//! Offset in map CRS coordinates at which our 3D world has origin (0,0,0)
225+
QgsVector3D mOrigin;
227226
QgsCoordinateReferenceSystem mCrs; //!< Destination coordinate system of the world
228227
QColor mBackgroundColor = Qt::black; //!< Background color of the scene
229228
QColor mSelectionColor; //!< Color to be used for selected map features

‎src/3d/qgs3dutils.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ QList<QVector3D> Qgs3DUtils::positions( const Qgs3DMapSettings &map, QgsVectorLa
194194
h = terrainZ + geomZ;
195195
break;
196196
}
197-
positions.append( QVector3D( pt.x() - map.originX(), h, -( pt.y() - map.originY() ) ) );
197+
positions.append( QVector3D( pt.x() - map.origin().x(), h, -( pt.y() - map.origin().y() ) ) );
198198
//qDebug() << positions.last();
199199
}
200200
}
@@ -255,3 +255,39 @@ bool Qgs3DUtils::isCullable( const QgsAABB &bbox, const QMatrix4x4 &viewProjecti
255255
return out;
256256
}
257257

258+
QgsVector3D Qgs3DUtils::mapToWorldCoordinates( const QgsVector3D &mapCoords, const QgsVector3D &origin )
259+
{
260+
return QgsVector3D( mapCoords.x() - origin.x(),
261+
mapCoords.z() - origin.z(),
262+
-( mapCoords.y() - origin.y() ) );
263+
264+
}
265+
266+
QgsVector3D Qgs3DUtils::worldToMapCoordinates( const QgsVector3D &worldCoords, const QgsVector3D &origin )
267+
{
268+
return QgsVector3D( worldCoords.x() + origin.x(),
269+
-worldCoords.z() + origin.y(),
270+
worldCoords.y() + origin.z() );
271+
}
272+
273+
QgsVector3D Qgs3DUtils::transformWorldCoordinates( const QgsVector3D &worldPoint1, const QgsVector3D &origin1, const QgsCoordinateReferenceSystem &crs1, const QgsVector3D &origin2, const QgsCoordinateReferenceSystem &crs2 )
274+
{
275+
QgsVector3D mapPoint1 = worldToMapCoordinates( worldPoint1, origin1 );
276+
QgsVector3D mapPoint2 = mapPoint1;
277+
if ( crs1 != crs2 )
278+
{
279+
// reproject if necessary
280+
QgsCoordinateTransform ct( crs1, crs2 );
281+
try
282+
{
283+
QgsPointXY pt = ct.transform( QgsPointXY( mapPoint1.x(), mapPoint1.y() ) );
284+
mapPoint2.set( pt.x(), pt.y(), mapPoint1.z() );
285+
}
286+
catch ( const QgsCsException & )
287+
{
288+
// bad luck, can't reproject for some reason
289+
}
290+
}
291+
return mapToWorldCoordinates( mapPoint2, origin2 );
292+
}
293+

‎src/3d/qgs3dutils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ class _3D_EXPORT Qgs3DUtils
8484
This is used to perform object culling checks.
8585
*/
8686
static bool isCullable( const QgsAABB &bbox, const QMatrix4x4 &viewProjectionMatrix );
87+
88+
//! Converts map coordinates to 3D world coordinates (applies offset and turns (x,y,z) into (x,-z,y))
89+
static QgsVector3D mapToWorldCoordinates( const QgsVector3D &mapCoords, const QgsVector3D &origin );
90+
//! Converts 3D world coordinates to map coordinates (applies offset and turns (x,y,z) into (x,-z,y))
91+
static QgsVector3D worldToMapCoordinates( const QgsVector3D &worldCoords, const QgsVector3D &origin );
92+
93+
//! Transforms a world point from (origin1, crs1) to (origin2, crs2)
94+
static QgsVector3D transformWorldCoordinates( const QgsVector3D &worldPoint1, const QgsVector3D &origin1, const QgsCoordinateReferenceSystem &crs1, const QgsVector3D &origin2, const QgsCoordinateReferenceSystem &crs2 );
8795
};
8896

8997
#endif // QGS3DUTILS_H

‎src/3d/qgscameracontroller.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
***************************************************************************/
1515

1616
#include "qgscameracontroller.h"
17+
#include "qgsvector3d.h"
1718

1819
#include "qgis.h"
1920

@@ -295,9 +296,14 @@ void QgsCameraController::setViewFromTop( float worldX, float worldY, float dist
295296
emit cameraChanged();
296297
}
297298

298-
void QgsCameraController::translateWorld( const QVector3D &vWorld )
299+
QgsVector3D QgsCameraController::lookingAtPoint() const
299300
{
300-
setCameraData( mCameraData.x - vWorld.x(), mCameraData.y + vWorld.y(), mCameraData.dist, mCameraData.pitch, mCameraData.yaw );
301+
return QgsVector3D( mCameraData.x, 0, mCameraData.y );
302+
}
303+
304+
void QgsCameraController::setLookingAtPoint( const QgsVector3D &point )
305+
{
306+
setCameraData( point.x(), point.z(), mCameraData.dist, mCameraData.pitch, mCameraData.yaw );
301307
emit cameraChanged();
302308
}
303309

‎src/3d/qgscameracontroller.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <Qt3DInput>
2323
#include <Qt3DRender>
2424

25+
class QgsVector3D;
2526

2627
/**
2728
* \ingroup 3d
@@ -60,8 +61,10 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
6061
//! Sets camera to look down towards given point in world coordinate, in given distance from plane with zero elevation
6162
void setViewFromTop( float worldX, float worldY, float distance, float yaw = 0 );
6263

63-
//! Moves the point toward which the camera is looking - this is used when world origin changes (e.g. after terrain generator changes)
64-
void translateWorld( const QVector3D &vWorld );
64+
//! Returns the point in the world coordinates towards which the camera is looking
65+
QgsVector3D lookingAtPoint() const;
66+
//! Sets the point toward which the camera is looking - this is used when world origin changes (e.g. after terrain generator changes)
67+
void setLookingAtPoint( const QgsVector3D &point );
6568

6669
private:
6770
void setCameraData( float x, float y, float dist, float pitch = 0, float yaw = 0 );

‎src/3d/qgsvector3d.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/***************************************************************************
2+
qgsvector3d.h
3+
--------------------------------------
4+
Date : November 2017
5+
Copyright : (C) 2017 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsvector3d.h"

‎src/3d/qgsvector3d.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/***************************************************************************
2+
qgsvector3d.h
3+
--------------------------------------
4+
Date : November 2017
5+
Copyright : (C) 2017 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
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 QGSVECTOR3D_H
17+
#define QGSVECTOR3D_H
18+
19+
#include "qgis_3d.h"
20+
21+
/**
22+
* \ingroup 3d
23+
* Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precision
24+
* instead of single precision floating point numbers.
25+
*
26+
* \since QGIS 3.0
27+
*/
28+
class _3D_EXPORT QgsVector3D
29+
{
30+
public:
31+
//! Constructs a null vector
32+
QgsVector3D() = default;
33+
34+
//! Constructs a vector from given coordinates
35+
QgsVector3D( double x, double y, double z )
36+
: mX( x ), mY( y ), mZ( z ) {}
37+
38+
//! Returns true if all three coordinates are zero
39+
bool isNull() const { return mX == 0 && mY == 0 && mZ == 0; }
40+
41+
//! Returns X coordinate
42+
double x() const { return mX; }
43+
//! Returns Y coordinate
44+
double y() const { return mY; }
45+
//! Returns Z coordinate
46+
double z() const { return mZ; }
47+
48+
//! Sets vector coordinates
49+
void set( double x, double y, double z )
50+
{
51+
mX = x;
52+
mY = y;
53+
mZ = z;
54+
}
55+
56+
bool operator==( const QgsVector3D &other ) const
57+
{
58+
return mX == other.mX && mY == other.mY && mZ == other.mZ;
59+
}
60+
bool operator!=( const QgsVector3D &other ) const
61+
{
62+
return !operator==( other );
63+
}
64+
65+
//! Returns sum of two vectors
66+
QgsVector3D operator+( const QgsVector3D &other )
67+
{
68+
return QgsVector3D( mX + other.mX, mY + other.mY, mZ + other.mZ );
69+
}
70+
71+
//! Returns difference of two vectors
72+
QgsVector3D operator-( const QgsVector3D &other )
73+
{
74+
return QgsVector3D( mX - other.mX, mY - other.mY, mZ - other.mZ );
75+
}
76+
77+
private:
78+
double mX = 0, mY = 0, mZ = 0;
79+
};
80+
81+
#endif // QGSVECTOR3D_H

‎src/3d/symbols/qgsline3dsymbol_p.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ QgsLine3DSymbolEntityNode::QgsLine3DSymbolEntityNode( const Qgs3DMapSettings &ma
9393

9494
Qt3DRender::QGeometryRenderer *QgsLine3DSymbolEntityNode::renderer( const Qgs3DMapSettings &map, const QgsLine3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request )
9595
{
96-
QgsPointXY origin( map.originX(), map.originY() );
96+
QgsPointXY origin( map.origin().x(), map.origin().y() );
9797

9898
// TODO: configurable
9999
int nSegments = 4;

‎src/3d/symbols/qgspolygon3dsymbol_p.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ QgsPolygon3DSymbolEntityNode::QgsPolygon3DSymbolEntityNode( const Qgs3DMapSettin
121121

122122
Qt3DRender::QGeometryRenderer *QgsPolygon3DSymbolEntityNode::renderer( const Qgs3DMapSettings &map, const QgsPolygon3DSymbol &symbol, const QgsVectorLayer *layer, const QgsFeatureRequest &request )
123123
{
124-
QgsPointXY origin( map.originX(), map.originY() );
124+
QgsPointXY origin( map.origin().x(), map.origin().y() );
125125
QList<QgsPolygon *> polygons;
126126
QList<float> extrusionHeightPerPolygon; // will stay empty if not needed per polygon
127127

‎src/3d/terrain/qgsdemterraingenerator.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,16 @@ QgsRasterLayer *QgsDemTerrainGenerator::layer() const
3535
return qobject_cast<QgsRasterLayer *>( mLayer.layer.data() );
3636
}
3737

38+
void QgsDemTerrainGenerator::setCrs( const QgsCoordinateReferenceSystem &crs )
39+
{
40+
mCrs = crs;
41+
updateGenerator();
42+
}
43+
3844
QgsTerrainGenerator *QgsDemTerrainGenerator::clone() const
3945
{
4046
QgsDemTerrainGenerator *cloned = new QgsDemTerrainGenerator;
47+
cloned->mCrs = mCrs;
4148
cloned->mLayer = mLayer;
4249
cloned->mResolution = mResolution;
4350
cloned->mSkirtHeight = mSkirtHeight;
@@ -66,13 +73,17 @@ void QgsDemTerrainGenerator::writeXml( QDomElement &elem ) const
6673
elem.setAttribute( "layer", mLayer.layerId );
6774
elem.setAttribute( "resolution", mResolution );
6875
elem.setAttribute( "skirt-height", mSkirtHeight );
76+
77+
// crs is not read/written - it should be the same as destination crs of the map
6978
}
7079

7180
void QgsDemTerrainGenerator::readXml( const QDomElement &elem )
7281
{
7382
mLayer = QgsMapLayerRef( elem.attribute( "layer" ) );
7483
mResolution = elem.attribute( "resolution" ).toInt();
7584
mSkirtHeight = elem.attribute( "skirt-height" ).toFloat();
85+
86+
// crs is not read/written - it should be the same as destination crs of the map
7687
}
7788

7889
void QgsDemTerrainGenerator::resolveReferences( const QgsProject &project )
@@ -91,7 +102,11 @@ void QgsDemTerrainGenerator::updateGenerator()
91102
QgsRasterLayer *dem = layer();
92103
if ( dem )
93104
{
94-
mTerrainTilingScheme = QgsTilingScheme( dem->extent(), dem->crs() );
105+
QgsRectangle te = dem->extent();
106+
QgsCoordinateTransform terrainToMapTransform( dem->crs(), mCrs );
107+
te = terrainToMapTransform.transformBoundingBox( te );
108+
109+
mTerrainTilingScheme = QgsTilingScheme( te, mCrs );
95110
delete mHeightMapGenerator;
96111
mHeightMapGenerator = new QgsDemHeightMapGenerator( dem, mTerrainTilingScheme, mResolution );
97112
}

‎src/3d/terrain/qgsdemterraingenerator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class _3D_EXPORT QgsDemTerrainGenerator : public QgsTerrainGenerator
4545
//! Returns raster layer with elevation model to be used for terrain generation
4646
QgsRasterLayer *layer() const;
4747

48+
//! Sets CRS of the terrain
49+
void setCrs( const QgsCoordinateReferenceSystem &crs );
50+
4851
//! Sets resolution of the generator (how many elevation samples on one side of a terrain tile)
4952
void setResolution( int resolution ) { mResolution = resolution; updateGenerator(); }
5053
//! Returns resolution of the generator (how many elevation samples on one side of a terrain tile)
@@ -73,6 +76,7 @@ class _3D_EXPORT QgsDemTerrainGenerator : public QgsTerrainGenerator
7376

7477
QgsDemHeightMapGenerator *mHeightMapGenerator = nullptr;
7578

79+
QgsCoordinateReferenceSystem mCrs;
7680
//! source layer for heights
7781
QgsMapLayerRef mLayer;
7882
//! how many vertices to place on one side of the tile

‎src/3d/terrain/qgsdemterraintileloader_p.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *par
8282

8383
const Qgs3DMapSettings &map = terrain()->map3D();
8484
QgsRectangle extent = map.terrainGenerator()->tilingScheme().tileToExtent( mNode->tileX(), mNode->tileY(), mNode->tileZ() ); //node->extent;
85-
double x0 = extent.xMinimum() - map.originX();
86-
double y0 = extent.yMinimum() - map.originY();
85+
double x0 = extent.xMinimum() - map.origin().x();
86+
double y0 = extent.yMinimum() - map.origin().y();
8787
double side = extent.width();
8888
double half = side / 2;
8989

@@ -113,6 +113,7 @@ void QgsDemTerrainTileLoader::onHeightMapReady( int jobId, const QByteArray &hei
113113
// ---------------------
114114

115115
#include <qgsrasterlayer.h>
116+
#include <qgsrasterprojector.h>
116117
#include <QtConcurrent/QtConcurrentRun>
117118
#include <QFutureWatcher>
118119

@@ -132,13 +133,22 @@ QgsDemHeightMapGenerator::~QgsDemHeightMapGenerator()
132133

133134
#include <QElapsedTimer>
134135

135-
static QByteArray _readDtmData( QgsRasterDataProvider *provider, const QgsRectangle &extent, int res )
136+
static QByteArray _readDtmData( QgsRasterDataProvider *provider, const QgsRectangle &extent, int res, const QgsCoordinateReferenceSystem &destCrs )
136137
{
137138
QElapsedTimer t;
138139
t.start();
139140

140141
// TODO: use feedback object? (but GDAL currently does not support cancelation anyway)
141-
QgsRasterBlock *block = provider->block( 1, extent, res, res );
142+
QgsRasterInterface *input = provider;
143+
std::unique_ptr<QgsRasterProjector> projector;
144+
if ( provider->crs() != destCrs )
145+
{
146+
projector.reset( new QgsRasterProjector );
147+
projector->setCrs( provider->crs(), destCrs );
148+
projector->setInput( provider );
149+
input = projector.get();
150+
}
151+
QgsRasterBlock *block = input->block( 1, extent, res, res );
142152

143153
QByteArray data;
144154
if ( block )
@@ -168,7 +178,7 @@ int QgsDemHeightMapGenerator::render( int x, int y, int z )
168178
jd.extent = extent;
169179
jd.timer.start();
170180
// make a clone of the data provider so it is safe to use in worker thread
171-
jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution );
181+
jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution, mTilingScheme.crs() );
172182

173183
QFutureWatcher<QByteArray> *fw = new QFutureWatcher<QByteArray>;
174184
fw->setFuture( jd.future );

‎src/3d/terrain/qgsterraingenerator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ QgsAABB QgsTerrainGenerator::rootChunkBbox( const Qgs3DMapSettings &map ) const
2727

2828
float hMin, hMax;
2929
rootChunkHeightRange( hMin, hMax );
30-
return QgsAABB( te.xMinimum() - map.originX(), hMin * map.terrainVerticalScale(), -te.yMaximum() + map.originY(),
31-
te.xMaximum() - map.originX(), hMax * map.terrainVerticalScale(), -te.yMinimum() + map.originY() );
30+
return QgsAABB( te.xMinimum() - map.origin().x(), hMin * map.terrainVerticalScale(), -te.yMaximum() + map.origin().y(),
31+
te.xMaximum() - map.origin().x(), hMax * map.terrainVerticalScale(), -te.yMinimum() + map.origin().y() );
3232
}
3333

3434
float QgsTerrainGenerator::rootChunkError( const Qgs3DMapSettings &map ) const

‎src/app/3d/qgs3dmapcanvas.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void Qgs3DMapCanvas::resetView()
8585

8686
void Qgs3DMapCanvas::setViewFromTop( const QgsPointXY &center, float distance, float rotation )
8787
{
88-
float worldX = center.x() - mMap->originX();
89-
float worldY = center.y() - mMap->originY();
88+
float worldX = center.x() - mMap->origin().x();
89+
float worldY = center.y() - mMap->origin().y();
9090
mScene->cameraController()->setViewFromTop( worldX, -worldY, distance, rotation );
9191
}

‎src/app/3d/qgs3dmapcanvasdockwidget.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "qgsmapcanvas.h"
2323

2424
#include "qgs3dmapsettings.h"
25+
#include "qgs3dutils.h"
2526

2627
#include <QBoxLayout>
2728
#include <QDialog>
@@ -85,16 +86,22 @@ void Qgs3DMapCanvasDockWidget::configure()
8586
if ( !dlg.exec() )
8687
return;
8788

88-
double oldOriginX = map->originX(), oldOriginY = map->originY(), oldOriginZ = map->originZ();
89+
QgsVector3D oldOrigin = map->origin();
90+
QgsCoordinateReferenceSystem oldCrs = map->crs();
91+
QgsVector3D oldLookingAt = mCanvas->cameraController()->lookingAtPoint();
8992

9093
// update map
9194
w->apply();
9295

93-
double dx = map->originX() - oldOriginX, dy = map->originY() - oldOriginY, dz = map->originZ() - oldOriginZ;
94-
if ( dx || dy || dz )
96+
QgsVector3D p = Qgs3DUtils::transformWorldCoordinates(
97+
oldLookingAt,
98+
oldOrigin, oldCrs,
99+
map->origin(), map->crs() );
100+
101+
if ( p != oldLookingAt )
95102
{
96103
// apply() call has moved origin of the world so let's move camera so we look still at the same place
97-
mCanvas->cameraController()->translateWorld( QVector3D( dx, dy, dz ) );
104+
mCanvas->cameraController()->setLookingAtPoint( p );
98105
}
99106
}
100107

‎src/app/3d/qgs3dmapconfigwidget.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void Qgs3DMapConfigWidget::apply()
9090
if ( tGenNeedsUpdate )
9191
{
9292
QgsDemTerrainGenerator *demTerrainGen = new QgsDemTerrainGenerator;
93+
demTerrainGen->setCrs( mMap->crs() );
9394
demTerrainGen->setLayer( demLayer );
9495
demTerrainGen->setResolution( spinTerrainResolution->value() );
9596
demTerrainGen->setSkirtHeight( spinTerrainSkirtHeight->value() );
@@ -108,8 +109,13 @@ void Qgs3DMapConfigWidget::apply()
108109

109110
if ( needsUpdateOrigin )
110111
{
111-
QgsPointXY center = mMap->terrainGenerator()->extent().center();
112-
mMap->setOrigin( center.x(), center.y(), 0 );
112+
// reproject terrain's extent to map CRS
113+
QgsRectangle te = mMap->terrainGenerator()->extent();
114+
QgsCoordinateTransform terrainToMapTransform( mMap->terrainGenerator()->crs(), mMap->crs() );
115+
te = terrainToMapTransform.transformBoundingBox( te );
116+
117+
QgsPointXY center = te.center();
118+
mMap->setOrigin( QgsVector3D( center.x(), center.y(), 0 ) );
113119
}
114120

115121
mMap->setTerrainVerticalScale( spinTerrainScale->value() );
@@ -134,6 +140,7 @@ void Qgs3DMapConfigWidget::updateMaxZoomLevel()
134140
if ( demLayer )
135141
{
136142
QgsDemTerrainGenerator *demTerrainGen = new QgsDemTerrainGenerator;
143+
demTerrainGen->setCrs( mMap->crs() );
137144
demTerrainGen->setLayer( demLayer );
138145
demTerrainGen->setResolution( spinTerrainResolution->value() );
139146
tGen.reset( demTerrainGen );

‎src/app/qgisapp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10267,7 +10267,7 @@ void QgisApp::new3DMapCanvas()
1026710267

1026810268
Qgs3DMapSettings *map = new Qgs3DMapSettings;
1026910269
map->setCrs( prj->crs() );
10270-
map->setOrigin( fullExtent.center().x(), fullExtent.center().y(), 0 );
10270+
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
1027110271
map->setSelectionColor( mMapCanvas->selectionColor() );
1027210272
map->setBackgroundColor( mMapCanvas->canvasColor() );
1027310273
map->setLayers( mMapCanvas->layers() );

‎tests/src/3d/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ SET (util_SRCS)
88
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
99
${CMAKE_SOURCE_DIR}/tests/core #for render checker class
1010
${CMAKE_SOURCE_DIR}/src/3d
11+
${CMAKE_SOURCE_DIR}/src/3d/chunks
12+
${CMAKE_SOURCE_DIR}/src/3d/terrain
1113
${CMAKE_SOURCE_DIR}/src/core
1214
${CMAKE_SOURCE_DIR}/src/core/expression
1315
${CMAKE_SOURCE_DIR}/src/core/auth
@@ -68,4 +70,5 @@ MACRO (ADD_QGIS_TEST testname testsrc)
6870
# INSTALL_RPATH_USE_LINK_PATH true )
6971
ENDMACRO (ADD_QGIS_TEST)
7072

73+
ADD_QGIS_TEST(3dutilstest testqgs3dutils.cpp)
7174
ADD_QGIS_TEST(tessellatortest testqgstessellator.cpp)

‎tests/src/3d/testqgs3dutils.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/***************************************************************************
2+
testqgs3dutils.cpp
3+
----------------------
4+
Date : November 2017
5+
Copyright : (C) 2017 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgstest.h"
17+
18+
#include "qgs3dutils.h"
19+
20+
21+
/**
22+
* \ingroup UnitTests
23+
* This is a unit test for the node tool
24+
*/
25+
class TestQgs3DUtils : public QObject
26+
{
27+
Q_OBJECT
28+
public:
29+
TestQgs3DUtils() = default;
30+
31+
private slots:
32+
void initTestCase();// will be called before the first testfunction is executed.
33+
void cleanupTestCase();// will be called after the last testfunction was executed.
34+
35+
void testTransforms();
36+
37+
private:
38+
};
39+
40+
//runs before all tests
41+
void TestQgs3DUtils::initTestCase()
42+
{
43+
}
44+
45+
//runs after all tests
46+
void TestQgs3DUtils::cleanupTestCase()
47+
{
48+
}
49+
50+
void TestQgs3DUtils::testTransforms()
51+
{
52+
QgsVector3D map123( 1, 2, 3 );
53+
54+
QgsVector3D world123 = Qgs3DUtils::mapToWorldCoordinates( map123, QgsVector3D() );
55+
QCOMPARE( world123, QgsVector3D( 1, 3, -2 ) );
56+
57+
QgsVector3D world123map = Qgs3DUtils::worldToMapCoordinates( world123, QgsVector3D() );
58+
QCOMPARE( world123map, map123 );
59+
60+
// now with non-zero origin
61+
62+
QgsVector3D origin( -10, -20, -30 );
63+
64+
QgsVector3D world123x = Qgs3DUtils::mapToWorldCoordinates( map123, origin );
65+
QCOMPARE( world123x, QgsVector3D( 11, 33, -22 ) );
66+
67+
QgsVector3D world123xmap = Qgs3DUtils::worldToMapCoordinates( world123x, origin );
68+
QCOMPARE( world123xmap, map123 );
69+
70+
//
71+
// transform world point from one system to another
72+
//
73+
74+
QgsVector3D worldPoint1( 5, 7, -6 );
75+
QgsVector3D origin1( 10, 20, 30 );
76+
QgsVector3D origin2( 1, 2, 3 );
77+
QgsVector3D worldPoint2 = Qgs3DUtils::transformWorldCoordinates( worldPoint1, origin1, QgsCoordinateReferenceSystem(), origin2, QgsCoordinateReferenceSystem() );
78+
QCOMPARE( worldPoint2, QgsVector3D( 14, 34, -24 ) );
79+
// verify that both are the same map point
80+
QgsVector3D mapPoint1 = Qgs3DUtils::worldToMapCoordinates( worldPoint1, origin1 );
81+
QgsVector3D mapPoint2 = Qgs3DUtils::worldToMapCoordinates( worldPoint2, origin2 );
82+
QCOMPARE( mapPoint1, mapPoint2 );
83+
}
84+
85+
QGSTEST_MAIN( TestQgs3DUtils )
86+
#include "testqgs3dutils.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.