Skip to content

Commit

Permalink
[3d] Cleaned up code for camera translation + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Nov 29, 2017
1 parent e214c6f commit 62543eb
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 14 deletions.
8 changes: 2 additions & 6 deletions src/3d/qgs3dmapsettings.cpp
Expand Up @@ -211,16 +211,12 @@ void Qgs3DMapSettings::resolveReferences( const QgsProject &project )

QgsVector3D Qgs3DMapSettings::mapToWorldCoordinates( const QgsVector3D &mapCoords ) const
{
return QgsVector3D( mapCoords.x() - mOrigin.x(),
-( mapCoords.z() - mOrigin.z() ),
mapCoords.y() - mOrigin.y() );
return Qgs3DUtils::mapToWorldCoordinates( mapCoords, mOrigin );
}

QgsVector3D Qgs3DMapSettings::worldToMapCoordinates( const QgsVector3D &worldCoords ) const
{
return QgsVector3D( worldCoords.x() + mOrigin.x(),
-( worldCoords.z() + mOrigin.z() ),
worldCoords.y() + mOrigin.y() );
return Qgs3DUtils::worldToMapCoordinates( worldCoords, mOrigin );
}

void Qgs3DMapSettings::setCrs( const QgsCoordinateReferenceSystem &crs )
Expand Down
36 changes: 36 additions & 0 deletions src/3d/qgs3dutils.cpp
Expand Up @@ -255,3 +255,39 @@ bool Qgs3DUtils::isCullable( const QgsAABB &bbox, const QMatrix4x4 &viewProjecti
return out;
}

QgsVector3D Qgs3DUtils::mapToWorldCoordinates( const QgsVector3D &mapCoords, const QgsVector3D &origin )
{
return QgsVector3D( mapCoords.x() - origin.x(),
mapCoords.z() - origin.z(),
-( mapCoords.y() - origin.y() ) );

}

QgsVector3D Qgs3DUtils::worldToMapCoordinates( const QgsVector3D &worldCoords, const QgsVector3D &origin )
{
return QgsVector3D( worldCoords.x() + origin.x(),
-worldCoords.z() + origin.y(),
worldCoords.y() + origin.z() );
}

QgsVector3D Qgs3DUtils::transformWorldCoordinates( const QgsVector3D &worldPoint1, const QgsVector3D &origin1, const QgsCoordinateReferenceSystem &crs1, const QgsVector3D &origin2, const QgsCoordinateReferenceSystem &crs2 )
{
QgsVector3D mapPoint1 = worldToMapCoordinates( worldPoint1, origin1 );
QgsVector3D mapPoint2 = mapPoint1;
if ( crs1 != crs2 )
{
// reproject if necessary
QgsCoordinateTransform ct( crs1, crs2 );
try
{
QgsPointXY pt = ct.transform( QgsPointXY( mapPoint1.x(), mapPoint1.y() ) );
mapPoint2.set( pt.x(), pt.y(), mapPoint1.z() );
}
catch ( const QgsCsException & )
{
// bad luck, can't reproject for some reason
}
}
return mapToWorldCoordinates( mapPoint2, origin2 );
}

8 changes: 8 additions & 0 deletions src/3d/qgs3dutils.h
Expand Up @@ -84,6 +84,14 @@ class _3D_EXPORT Qgs3DUtils
This is used to perform object culling checks.
*/
static bool isCullable( const QgsAABB &bbox, const QMatrix4x4 &viewProjectionMatrix );

//! Converts map coordinates to 3D world coordinates (applies offset and turns (x,y,z) into (x,-z,y))
static QgsVector3D mapToWorldCoordinates( const QgsVector3D &mapCoords, const QgsVector3D &origin );
//! Converts 3D world coordinates to map coordinates (applies offset and turns (x,y,z) into (x,-z,y))
static QgsVector3D worldToMapCoordinates( const QgsVector3D &worldCoords, const QgsVector3D &origin );

//! Transforms a world point from (origin1, crs1) to (origin2, crs2)
static QgsVector3D transformWorldCoordinates( const QgsVector3D &worldPoint1, const QgsVector3D &origin1, const QgsCoordinateReferenceSystem &crs1, const QgsVector3D &origin2, const QgsCoordinateReferenceSystem &crs2 );
};

#endif // QGS3DUTILS_H
9 changes: 7 additions & 2 deletions src/3d/qgscameracontroller.cpp
Expand Up @@ -296,9 +296,14 @@ void QgsCameraController::setViewFromTop( float worldX, float worldY, float dist
emit cameraChanged();
}

void QgsCameraController::translateWorld( const QgsVector3D &vWorld )
QgsVector3D QgsCameraController::lookingAtPoint() const
{
setCameraData( mCameraData.x - vWorld.x(), mCameraData.y + vWorld.y(), mCameraData.dist, mCameraData.pitch, mCameraData.yaw );
return QgsVector3D( mCameraData.x, 0, mCameraData.y );
}

void QgsCameraController::setLookingAtPoint( const QgsVector3D &point )
{
setCameraData( point.x(), point.z(), mCameraData.dist, mCameraData.pitch, mCameraData.yaw );
emit cameraChanged();
}

Expand Down
6 changes: 4 additions & 2 deletions src/3d/qgscameracontroller.h
Expand Up @@ -61,8 +61,10 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
//! Sets camera to look down towards given point in world coordinate, in given distance from plane with zero elevation
void setViewFromTop( float worldX, float worldY, float distance, float yaw = 0 );

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

private:
void setCameraData( float x, float y, float dist, float pitch = 0, float yaw = 0 );
Expand Down
9 changes: 9 additions & 0 deletions src/3d/qgsvector3d.h
Expand Up @@ -52,6 +52,15 @@ class _3D_EXPORT QgsVector3D
mZ = z;
}

bool operator==( const QgsVector3D &other ) const
{
return mX == other.mX && mY == other.mY && mZ == other.mZ;
}
bool operator!=( const QgsVector3D &other ) const
{
return !operator==( other );
}

//! Returns sum of two vectors
QgsVector3D operator+( const QgsVector3D &other )
{
Expand Down
13 changes: 10 additions & 3 deletions src/app/3d/qgs3dmapcanvasdockwidget.cpp
Expand Up @@ -22,6 +22,7 @@
#include "qgsmapcanvas.h"

#include "qgs3dmapsettings.h"
#include "qgs3dutils.h"

#include <QBoxLayout>
#include <QDialog>
Expand Down Expand Up @@ -86,15 +87,21 @@ void Qgs3DMapCanvasDockWidget::configure()
return;

QgsVector3D oldOrigin = map->origin();
QgsCoordinateReferenceSystem oldCrs = map->crs();
QgsVector3D oldLookingAt = mCanvas->cameraController()->lookingAtPoint();

// update map
w->apply();

QgsVector3D d = map->origin() - oldOrigin;
if ( !d.isNull() )
QgsVector3D p = Qgs3DUtils::transformWorldCoordinates(
oldLookingAt,
oldOrigin, oldCrs,
map->origin(), map->crs() );

if ( p != oldLookingAt )
{
// apply() call has moved origin of the world so let's move camera so we look still at the same place
mCanvas->cameraController()->translateWorld( d );
mCanvas->cameraController()->setLookingAtPoint( p );
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/app/3d/qgs3dmapconfigwidget.cpp
Expand Up @@ -108,7 +108,12 @@ void Qgs3DMapConfigWidget::apply()

if ( needsUpdateOrigin )
{
QgsPointXY center = mMap->terrainGenerator()->extent().center();
// reproject terrain's extent to map CRS
QgsRectangle te = mMap->terrainGenerator()->extent();
QgsCoordinateTransform terrainToMapTransform( mMap->terrainGenerator()->crs(), mMap->crs() );
te = terrainToMapTransform.transformBoundingBox( te );

QgsPointXY center = te.center();
mMap->setOrigin( QgsVector3D( center.x(), center.y(), 0 ) );
}

Expand Down
3 changes: 3 additions & 0 deletions tests/src/3d/CMakeLists.txt
Expand Up @@ -8,6 +8,8 @@ SET (util_SRCS)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/tests/core #for render checker class
${CMAKE_SOURCE_DIR}/src/3d
${CMAKE_SOURCE_DIR}/src/3d/chunks
${CMAKE_SOURCE_DIR}/src/3d/terrain
${CMAKE_SOURCE_DIR}/src/core
${CMAKE_SOURCE_DIR}/src/core/expression
${CMAKE_SOURCE_DIR}/src/core/auth
Expand Down Expand Up @@ -68,4 +70,5 @@ MACRO (ADD_QGIS_TEST testname testsrc)
# INSTALL_RPATH_USE_LINK_PATH true )
ENDMACRO (ADD_QGIS_TEST)

ADD_QGIS_TEST(3dutilstest testqgs3dutils.cpp)
ADD_QGIS_TEST(tessellatortest testqgstessellator.cpp)
86 changes: 86 additions & 0 deletions tests/src/3d/testqgs3dutils.cpp
@@ -0,0 +1,86 @@
/***************************************************************************
testqgs3dutils.cpp
----------------------
Date : November 2017
Copyright : (C) 2017 by Martin Dobias
Email : wonder dot sk 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 "qgstest.h"

#include "qgs3dutils.h"


/**
* \ingroup UnitTests
* This is a unit test for the node tool
*/
class TestQgs3DUtils : public QObject
{
Q_OBJECT
public:
TestQgs3DUtils() = default;

private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.

void testTransforms();

private:
};

//runs before all tests
void TestQgs3DUtils::initTestCase()
{
}

//runs after all tests
void TestQgs3DUtils::cleanupTestCase()
{
}

void TestQgs3DUtils::testTransforms()
{
QgsVector3D map123( 1, 2, 3 );

QgsVector3D world123 = Qgs3DUtils::mapToWorldCoordinates( map123, QgsVector3D() );
QCOMPARE( world123, QgsVector3D( 1, 3, -2 ) );

QgsVector3D world123map = Qgs3DUtils::worldToMapCoordinates( world123, QgsVector3D() );
QCOMPARE( world123map, map123 );

// now with non-zero origin

QgsVector3D origin( -10, -20, -30 );

QgsVector3D world123x = Qgs3DUtils::mapToWorldCoordinates( map123, origin );
QCOMPARE( world123x, QgsVector3D( 11, 33, -22 ) );

QgsVector3D world123xmap = Qgs3DUtils::worldToMapCoordinates( world123x, origin );
QCOMPARE( world123xmap, map123 );

//
// transform world point from one system to another
//

QgsVector3D worldPoint1( 5, 7, -6 );
QgsVector3D origin1( 10, 20, 30 );
QgsVector3D origin2( 1, 2, 3 );
QgsVector3D worldPoint2 = Qgs3DUtils::transformWorldCoordinates( worldPoint1, origin1, QgsCoordinateReferenceSystem(), origin2, QgsCoordinateReferenceSystem() );
QCOMPARE( worldPoint2, QgsVector3D( 14, 34, -24 ) );
// verify that both are the same map point
QgsVector3D mapPoint1 = Qgs3DUtils::worldToMapCoordinates( worldPoint1, origin1 );
QgsVector3D mapPoint2 = Qgs3DUtils::worldToMapCoordinates( worldPoint2, origin2 );
QCOMPARE( mapPoint1, mapPoint2 );
}

QGSTEST_MAIN( TestQgs3DUtils )
#include "testqgs3dutils.moc"

0 comments on commit 62543eb

Please sign in to comment.