Skip to content

Commit 62543eb

Browse files
committed
[3d] Cleaned up code for camera translation + tests
1 parent e214c6f commit 62543eb

10 files changed

+171
-14
lines changed

src/3d/qgs3dmapsettings.cpp

+2-6
Original file line numberDiff line numberDiff line change
@@ -211,16 +211,12 @@ void Qgs3DMapSettings::resolveReferences( const QgsProject &project )
211211

212212
QgsVector3D Qgs3DMapSettings::mapToWorldCoordinates( const QgsVector3D &mapCoords ) const
213213
{
214-
return QgsVector3D( mapCoords.x() - mOrigin.x(),
215-
-( mapCoords.z() - mOrigin.z() ),
216-
mapCoords.y() - mOrigin.y() );
214+
return Qgs3DUtils::mapToWorldCoordinates( mapCoords, mOrigin );
217215
}
218216

219217
QgsVector3D Qgs3DMapSettings::worldToMapCoordinates( const QgsVector3D &worldCoords ) const
220218
{
221-
return QgsVector3D( worldCoords.x() + mOrigin.x(),
222-
-( worldCoords.z() + mOrigin.z() ),
223-
worldCoords.y() + mOrigin.y() );
219+
return Qgs3DUtils::worldToMapCoordinates( worldCoords, mOrigin );
224220
}
225221

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

src/3d/qgs3dutils.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -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

+8
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

+7-2
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,14 @@ void QgsCameraController::setViewFromTop( float worldX, float worldY, float dist
296296
emit cameraChanged();
297297
}
298298

299-
void QgsCameraController::translateWorld( const QgsVector3D &vWorld )
299+
QgsVector3D QgsCameraController::lookingAtPoint() const
300300
{
301-
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 );
302307
emit cameraChanged();
303308
}
304309

src/3d/qgscameracontroller.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
6161
//! Sets camera to look down towards given point in world coordinate, in given distance from plane with zero elevation
6262
void setViewFromTop( float worldX, float worldY, float distance, float yaw = 0 );
6363

64-
//! Moves the point toward which the camera is looking - this is used when world origin changes (e.g. after terrain generator changes)
65-
void translateWorld( const QgsVector3D &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 );
6668

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

src/3d/qgsvector3d.h

+9
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ class _3D_EXPORT QgsVector3D
5252
mZ = z;
5353
}
5454

55+
bool operator==( const QgsVector3D &other ) const
56+
{
57+
return mX == other.mX && mY == other.mY && mZ == other.mZ;
58+
}
59+
bool operator!=( const QgsVector3D &other ) const
60+
{
61+
return !operator==( other );
62+
}
63+
5564
//! Returns sum of two vectors
5665
QgsVector3D operator+( const QgsVector3D &other )
5766
{

src/app/3d/qgs3dmapcanvasdockwidget.cpp

+10-3
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>
@@ -86,15 +87,21 @@ void Qgs3DMapCanvasDockWidget::configure()
8687
return;
8788

8889
QgsVector3D oldOrigin = map->origin();
90+
QgsCoordinateReferenceSystem oldCrs = map->crs();
91+
QgsVector3D oldLookingAt = mCanvas->cameraController()->lookingAtPoint();
8992

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

93-
QgsVector3D d = map->origin() - oldOrigin;
94-
if ( !d.isNull() )
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( d );
104+
mCanvas->cameraController()->setLookingAtPoint( p );
98105
}
99106
}
100107

src/app/3d/qgs3dmapconfigwidget.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,12 @@ void Qgs3DMapConfigWidget::apply()
108108

109109
if ( needsUpdateOrigin )
110110
{
111-
QgsPointXY center = mMap->terrainGenerator()->extent().center();
111+
// reproject terrain's extent to map CRS
112+
QgsRectangle te = mMap->terrainGenerator()->extent();
113+
QgsCoordinateTransform terrainToMapTransform( mMap->terrainGenerator()->crs(), mMap->crs() );
114+
te = terrainToMapTransform.transformBoundingBox( te );
115+
116+
QgsPointXY center = te.center();
112117
mMap->setOrigin( QgsVector3D( center.x(), center.y(), 0 ) );
113118
}
114119

tests/src/3d/CMakeLists.txt

+3
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

+86
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)