Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Introduce QgsVector3D for 3D vectors with double precision
QVector3D with single precision is not always enough (it has only ~7 significant digits)
  • Loading branch information
wonder-sk committed Nov 27, 2017
1 parent 721551f commit e214c6f
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 43 deletions.
2 changes: 2 additions & 0 deletions src/3d/CMakeLists.txt
Expand Up @@ -11,6 +11,7 @@ SET(QGIS_3D_SRCS
qgstessellatedpolygongeometry.cpp
qgstessellator.cpp
qgstilingscheme.cpp
qgsvector3d.cpp
qgsvectorlayer3drenderer.cpp

chunks/qgschunkboundsentity_p.cpp
Expand Down Expand Up @@ -84,6 +85,7 @@ SET(QGIS_3D_HDRS
qgstessellatedpolygongeometry.h
qgstessellator.h
qgstilingscheme.h
qgsvector3d.h
qgsvectorlayer3drenderer.h

chunks/qgschunkboundsentity_p.h
Expand Down
32 changes: 19 additions & 13 deletions src/3d/qgs3dmapsettings.cpp
Expand Up @@ -28,9 +28,7 @@

Qgs3DMapSettings::Qgs3DMapSettings( const Qgs3DMapSettings &other )
: QObject()
, mOriginX( other.mOriginX )
, mOriginY( other.mOriginY )
, mOriginZ( other.mOriginZ )
, mOrigin( other.mOrigin )
, mCrs( other.mCrs )
, mBackgroundColor( other.mBackgroundColor )
, mTerrainVerticalScale( other.mTerrainVerticalScale )
Expand Down Expand Up @@ -59,9 +57,10 @@ Qgs3DMapSettings::~Qgs3DMapSettings()
void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
QDomElement elemOrigin = elem.firstChildElement( "origin" );
mOriginX = elemOrigin.attribute( "x" ).toDouble();
mOriginY = elemOrigin.attribute( "y" ).toDouble();
mOriginZ = elemOrigin.attribute( "z" ).toDouble();
mOrigin = QgsVector3D(
elemOrigin.attribute( "x" ).toDouble(),
elemOrigin.attribute( "y" ).toDouble(),
elemOrigin.attribute( "z" ).toDouble() );

QDomElement elemCrs = elem.firstChildElement( "crs" );
mCrs.readXml( elemCrs );
Expand Down Expand Up @@ -139,9 +138,9 @@ QDomElement Qgs3DMapSettings::writeXml( QDomDocument &doc, const QgsReadWriteCon
QDomElement elem = doc.createElement( "qgis3d" );

QDomElement elemOrigin = doc.createElement( "origin" );
elemOrigin.setAttribute( "x", QString::number( mOriginX ) );
elemOrigin.setAttribute( "y", QString::number( mOriginY ) );
elemOrigin.setAttribute( "z", QString::number( mOriginZ ) );
elemOrigin.setAttribute( "x", QString::number( mOrigin.x() ) );
elemOrigin.setAttribute( "y", QString::number( mOrigin.y() ) );
elemOrigin.setAttribute( "z", QString::number( mOrigin.z() ) );
elem.appendChild( elemOrigin );

QDomElement elemCrs = doc.createElement( "crs" );
Expand Down Expand Up @@ -210,11 +209,18 @@ void Qgs3DMapSettings::resolveReferences( const QgsProject &project )
}
}

void Qgs3DMapSettings::setOrigin( double originX, double originY, double originZ )
QgsVector3D Qgs3DMapSettings::mapToWorldCoordinates( const QgsVector3D &mapCoords ) const
{
mOriginX = originX;
mOriginY = originY;
mOriginZ = originZ;
return QgsVector3D( mapCoords.x() - mOrigin.x(),
-( mapCoords.z() - mOrigin.z() ),
mapCoords.y() - mOrigin.y() );
}

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

void Qgs3DMapSettings::setCrs( const QgsCoordinateReferenceSystem &crs )
Expand Down
25 changes: 12 additions & 13 deletions src/3d/qgs3dmapsettings.h
Expand Up @@ -25,6 +25,7 @@
#include "qgscoordinatereferencesystem.h"
#include "qgsmaplayerref.h"
#include "qgsterraingenerator.h"
#include "qgsvector3d.h"

class QgsMapLayer;
class QgsRasterLayer;
Expand All @@ -37,6 +38,7 @@ class QgsProject;

class QDomElement;


/**
* \ingroup 3d
* Definition of the world
Expand Down Expand Up @@ -72,13 +74,14 @@ class _3D_EXPORT Qgs3DMapSettings : public QObject
* Need to look into more advanced techniques like "relative to center" or "relative to eye"
* to improve the precision.
*/
void setOrigin( double originX, double originY, double originZ );
//! Returns X coordinate in map CRS at which 3D scene has origin (zero)
double originX() const { return mOriginX; }
//! Returns Y coordinate in map CRS at which 3D scene has origin (zero)
double originY() const { return mOriginY; }
//! Returns Z coordinate in map CRS at which 3D scene has origin (zero)
double originZ() const { return mOriginZ; }
void setOrigin( const QgsVector3D &origin ) { mOrigin = origin; }
//! Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
QgsVector3D origin() const { return mOrigin; }

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

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

private:
//! X coordinate in map CRS at which our 3D world has origin (0,0,0)
double mOriginX = 0;
//! Y coordinate in map CRS at which our 3D world has origin (0,0,0)
double mOriginY = 0;
//! Z coordinate in map CRS at which our 3D world has origin (0,0,0)
double mOriginZ = 0;
//! Offset in map CRS coordinates at which our 3D world has origin (0,0,0)
QgsVector3D mOrigin;
QgsCoordinateReferenceSystem mCrs; //!< Destination coordinate system of the world
QColor mBackgroundColor = Qt::black; //!< Background color of the scene
QColor mSelectionColor; //!< Color to be used for selected map features
Expand Down
2 changes: 1 addition & 1 deletion src/3d/qgs3dutils.cpp
Expand Up @@ -194,7 +194,7 @@ QList<QVector3D> Qgs3DUtils::positions( const Qgs3DMapSettings &map, QgsVectorLa
h = terrainZ + geomZ;
break;
}
positions.append( QVector3D( pt.x() - map.originX(), h, -( pt.y() - map.originY() ) ) );
positions.append( QVector3D( pt.x() - map.origin().x(), h, -( pt.y() - map.origin().y() ) ) );
//qDebug() << positions.last();
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/3d/qgscameracontroller.cpp
Expand Up @@ -14,6 +14,7 @@
***************************************************************************/

#include "qgscameracontroller.h"
#include "qgsvector3d.h"

#include "qgis.h"

Expand Down Expand Up @@ -295,7 +296,7 @@ void QgsCameraController::setViewFromTop( float worldX, float worldY, float dist
emit cameraChanged();
}

void QgsCameraController::translateWorld( const QVector3D &vWorld )
void QgsCameraController::translateWorld( const QgsVector3D &vWorld )
{
setCameraData( mCameraData.x - vWorld.x(), mCameraData.y + vWorld.y(), mCameraData.dist, mCameraData.pitch, mCameraData.yaw );
emit cameraChanged();
Expand Down
3 changes: 2 additions & 1 deletion src/3d/qgscameracontroller.h
Expand Up @@ -22,6 +22,7 @@
#include <Qt3DInput>
#include <Qt3DRender>

class QgsVector3D;

/**
* \ingroup 3d
Expand Down Expand Up @@ -61,7 +62,7 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
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 QVector3D &vWorld );
void translateWorld( const QgsVector3D &vWorld );

private:
void setCameraData( float x, float y, float dist, float pitch = 0, float yaw = 0 );
Expand Down
16 changes: 16 additions & 0 deletions src/3d/qgsvector3d.cpp
@@ -0,0 +1,16 @@
/***************************************************************************
qgsvector3d.h
--------------------------------------
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 "qgsvector3d.h"
71 changes: 71 additions & 0 deletions src/3d/qgsvector3d.h
@@ -0,0 +1,71 @@
/***************************************************************************
qgsvector3d.h
--------------------------------------
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. *
* *
***************************************************************************/

#ifndef QGSVECTOR3D_H
#define QGSVECTOR3D_H

#include "qgis_3d.h"

/**
* Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precision
* instead of single precision floating point numbers.
*
* \note Added in QGIS 3.0
*/
class _3D_EXPORT QgsVector3D
{
public:
//! Constructs a null vector
QgsVector3D() = default;

//! Constructs a vector from given coordinates
QgsVector3D( double x, double y, double z )
: mX( x ), mY( y ), mZ( z ) {}

//! Returns true if all three coordinates are zero
bool isNull() const { return mX == 0 && mY == 0 && mZ == 0; }

//! Returns X coordinate
double x() const { return mX; }
//! Returns Y coordinate
double y() const { return mY; }
//! Returns Z coordinate
double z() const { return mZ; }

//! Sets vector coordinates
void set( double x, double y, double z )
{
mX = x;
mY = y;
mZ = z;
}

//! Returns sum of two vectors
QgsVector3D operator+( const QgsVector3D &other )
{
return QgsVector3D( mX + other.mX, mY + other.mY, mZ + other.mZ );
}

//! Returns difference of two vectors
QgsVector3D operator-( const QgsVector3D &other )
{
return QgsVector3D( mX - other.mX, mY - other.mY, mZ - other.mZ );
}

private:
double mX = 0, mY = 0, mZ = 0;
};

#endif // QGSVECTOR3D_H
2 changes: 1 addition & 1 deletion src/3d/symbols/qgsline3dsymbol_p.cpp
Expand Up @@ -93,7 +93,7 @@ QgsLine3DSymbolEntityNode::QgsLine3DSymbolEntityNode( const Qgs3DMapSettings &ma

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

// TODO: configurable
int nSegments = 4;
Expand Down
2 changes: 1 addition & 1 deletion src/3d/symbols/qgspolygon3dsymbol_p.cpp
Expand Up @@ -121,7 +121,7 @@ QgsPolygon3DSymbolEntityNode::QgsPolygon3DSymbolEntityNode( const Qgs3DMapSettin

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

Expand Down
4 changes: 2 additions & 2 deletions src/3d/terrain/qgsdemterraintileloader_p.cpp
Expand Up @@ -82,8 +82,8 @@ Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *par

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

Expand Down
4 changes: 2 additions & 2 deletions src/3d/terrain/qgsterraingenerator.cpp
Expand Up @@ -27,8 +27,8 @@ QgsAABB QgsTerrainGenerator::rootChunkBbox( const Qgs3DMapSettings &map ) const

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

float QgsTerrainGenerator::rootChunkError( const Qgs3DMapSettings &map ) const
Expand Down
4 changes: 2 additions & 2 deletions src/app/3d/qgs3dmapcanvas.cpp
Expand Up @@ -85,7 +85,7 @@ void Qgs3DMapCanvas::resetView()

void Qgs3DMapCanvas::setViewFromTop( const QgsPointXY &center, float distance, float rotation )
{
float worldX = center.x() - mMap->originX();
float worldY = center.y() - mMap->originY();
float worldX = center.x() - mMap->origin().x();
float worldY = center.y() - mMap->origin().y();
mScene->cameraController()->setViewFromTop( worldX, -worldY, distance, rotation );
}
8 changes: 4 additions & 4 deletions src/app/3d/qgs3dmapcanvasdockwidget.cpp
Expand Up @@ -85,16 +85,16 @@ void Qgs3DMapCanvasDockWidget::configure()
if ( !dlg.exec() )
return;

double oldOriginX = map->originX(), oldOriginY = map->originY(), oldOriginZ = map->originZ();
QgsVector3D oldOrigin = map->origin();

// update map
w->apply();

double dx = map->originX() - oldOriginX, dy = map->originY() - oldOriginY, dz = map->originZ() - oldOriginZ;
if ( dx || dy || dz )
QgsVector3D d = map->origin() - oldOrigin;
if ( !d.isNull() )
{
// apply() call has moved origin of the world so let's move camera so we look still at the same place
mCanvas->cameraController()->translateWorld( QVector3D( dx, dy, dz ) );
mCanvas->cameraController()->translateWorld( d );
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/3d/qgs3dmapconfigwidget.cpp
Expand Up @@ -109,7 +109,7 @@ void Qgs3DMapConfigWidget::apply()
if ( needsUpdateOrigin )
{
QgsPointXY center = mMap->terrainGenerator()->extent().center();
mMap->setOrigin( center.x(), center.y(), 0 );
mMap->setOrigin( QgsVector3D( center.x(), center.y(), 0 ) );
}

mMap->setTerrainVerticalScale( spinTerrainScale->value() );
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -10243,7 +10243,7 @@ void QgisApp::new3DMapCanvas()

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( prj->crs() );
map->setOrigin( fullExtent.center().x(), fullExtent.center().y(), 0 );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setSelectionColor( mMapCanvas->selectionColor() );
map->setBackgroundColor( mMapCanvas->canvasColor() );
map->setLayers( mMapCanvas->layers() );
Expand Down

0 comments on commit e214c6f

Please sign in to comment.