Skip to content
Permalink
Browse files

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 e214c6f4b854ea42a7e7dae9208ea67267ee5e8d
@@ -11,6 +11,7 @@ SET(QGIS_3D_SRCS
qgstessellatedpolygongeometry.cpp
qgstessellator.cpp
qgstilingscheme.cpp
qgsvector3d.cpp
qgsvectorlayer3drenderer.cpp

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

chunks/qgschunkboundsentity_p.h
@@ -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 )
@@ -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 );
@@ -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" );
@@ -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 )
@@ -25,6 +25,7 @@
#include "qgscoordinatereferencesystem.h"
#include "qgsmaplayerref.h"
#include "qgsterraingenerator.h"
#include "qgsvector3d.h"

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

class QDomElement;


/**
* \ingroup 3d
* Definition of the world
@@ -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 );
@@ -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
@@ -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();
}
}
@@ -14,6 +14,7 @@
***************************************************************************/

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

#include "qgis.h"

@@ -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();
@@ -22,6 +22,7 @@
#include <Qt3DInput>
#include <Qt3DRender>

class QgsVector3D;

/**
* \ingroup 3d
@@ -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 );
@@ -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"
@@ -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
@@ -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;
@@ -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

@@ -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;

@@ -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
@@ -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 );
}
@@ -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 );
}
}

@@ -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() );
@@ -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() );

0 comments on commit e214c6f

Please sign in to comment.
You can’t perform that action at this time.