Skip to content

Commit

Permalink
Decide number of zoom levels from max. allowed ground error
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Sep 15, 2017
1 parent 6df6681 commit 905222d
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 34 deletions.
62 changes: 54 additions & 8 deletions src/3d/map3d.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ Map3D::Map3D()
, originY( 0 ) , originY( 0 )
, originZ( 0 ) , originZ( 0 )
, backgroundColor( Qt::black ) , backgroundColor( Qt::black )
, tileTextureSize( 512 )
, maxTerrainError( 3.f )
, skybox( false ) , skybox( false )
, mTerrainVerticalScale( 1 ) , mTerrainVerticalScale( 1 )
, mMapTileResolution( 512 )
, mMaxTerrainScreenError( 3.f )
, mMaxTerrainGroundError( 1.f )
, mShowTerrainBoundingBoxes( false ) , mShowTerrainBoundingBoxes( false )
, mShowTerrainTileInfo( false ) , mShowTerrainTileInfo( false )
{ {
Expand All @@ -33,13 +34,14 @@ Map3D::Map3D( const Map3D &other )
, originZ( other.originZ ) , originZ( other.originZ )
, crs( other.crs ) , crs( other.crs )
, backgroundColor( other.backgroundColor ) , backgroundColor( other.backgroundColor )
, tileTextureSize( other.tileTextureSize )
, maxTerrainError( other.maxTerrainError )
, skybox( other.skybox ) , skybox( other.skybox )
, skyboxFileBase( other.skyboxFileBase ) , skyboxFileBase( other.skyboxFileBase )
, skyboxFileExtension( other.skyboxFileExtension ) , skyboxFileExtension( other.skyboxFileExtension )
, mTerrainVerticalScale( other.mTerrainVerticalScale ) , mTerrainVerticalScale( other.mTerrainVerticalScale )
, mTerrainGenerator( other.mTerrainGenerator ? other.mTerrainGenerator->clone() : nullptr ) , mTerrainGenerator( other.mTerrainGenerator ? other.mTerrainGenerator->clone() : nullptr )
, mMapTileResolution( other.mMapTileResolution )
, mMaxTerrainScreenError( other.mMaxTerrainScreenError )
, mMaxTerrainGroundError( other.mMaxTerrainGroundError )
, mShowTerrainBoundingBoxes( other.mShowTerrainBoundingBoxes ) , mShowTerrainBoundingBoxes( other.mShowTerrainBoundingBoxes )
, mShowTerrainTileInfo( other.mShowTerrainTileInfo ) , mShowTerrainTileInfo( other.mShowTerrainTileInfo )
, mLayers( other.mLayers ) , mLayers( other.mLayers )
Expand Down Expand Up @@ -67,8 +69,9 @@ void Map3D::readXml( const QDomElement &elem, const QgsReadWriteContext &context


QDomElement elemTerrain = elem.firstChildElement( "terrain" ); QDomElement elemTerrain = elem.firstChildElement( "terrain" );
mTerrainVerticalScale = elemTerrain.attribute( "exaggeration", "1" ).toFloat(); mTerrainVerticalScale = elemTerrain.attribute( "exaggeration", "1" ).toFloat();
tileTextureSize = elemTerrain.attribute( "texture-size", "512" ).toInt(); mMapTileResolution = elemTerrain.attribute( "texture-size", "512" ).toInt();
maxTerrainError = elemTerrain.attribute( "max-terrain-error", "3" ).toFloat(); mMaxTerrainScreenError = elemTerrain.attribute( "max-terrain-error", "3" ).toFloat();
mMaxTerrainGroundError = elemTerrain.attribute( "max-ground-error", "1" ).toFloat();
QDomElement elemMapLayers = elemTerrain.firstChildElement( "layers" ); QDomElement elemMapLayers = elemTerrain.firstChildElement( "layers" );
QDomElement elemMapLayer = elemMapLayers.firstChildElement( "layer" ); QDomElement elemMapLayer = elemMapLayers.firstChildElement( "layer" );
QList<QgsMapLayerRef> mapLayers; QList<QgsMapLayerRef> mapLayers;
Expand Down Expand Up @@ -147,8 +150,9 @@ QDomElement Map3D::writeXml( QDomDocument &doc, const QgsReadWriteContext &conte


QDomElement elemTerrain = doc.createElement( "terrain" ); QDomElement elemTerrain = doc.createElement( "terrain" );
elemTerrain.setAttribute( "exaggeration", QString::number( mTerrainVerticalScale ) ); elemTerrain.setAttribute( "exaggeration", QString::number( mTerrainVerticalScale ) );
elemTerrain.setAttribute( "texture-size", tileTextureSize ); elemTerrain.setAttribute( "texture-size", mMapTileResolution );
elemTerrain.setAttribute( "max-terrain-error", QString::number( maxTerrainError ) ); elemTerrain.setAttribute( "max-terrain-error", QString::number( mMaxTerrainScreenError ) );
elemTerrain.setAttribute( "max-ground-error", QString::number( mMaxTerrainGroundError ) );
QDomElement elemMapLayers = doc.createElement( "layers" ); QDomElement elemMapLayers = doc.createElement( "layers" );
Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers ) Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
{ {
Expand Down Expand Up @@ -247,6 +251,48 @@ QList<QgsMapLayer *> Map3D::layers() const
return lst; return lst;
} }


void Map3D::setMapTileResolution( int res )
{
if ( mMapTileResolution == res )
return;

mMapTileResolution = res;
emit mapTileResolutionChanged();
}

int Map3D::mapTileResolution() const
{
return mMapTileResolution;
}

void Map3D::setMaxTerrainScreenError( float error )
{
if ( mMaxTerrainScreenError == error )
return;

mMaxTerrainScreenError = error;
emit maxTerrainScreenErrorChanged();
}

float Map3D::maxTerrainScreenError() const
{
return mMaxTerrainScreenError;
}

void Map3D::setMaxTerrainGroundError( float error )
{
if ( mMaxTerrainGroundError == error )
return;

mMaxTerrainGroundError = error;
emit maxTerrainGroundErrorChanged();
}

float Map3D::maxTerrainGroundError() const
{
return mMaxTerrainGroundError;
}

void Map3D::setTerrainGenerator( TerrainGenerator *gen ) void Map3D::setTerrainGenerator( TerrainGenerator *gen )
{ {
mTerrainGenerator.reset( gen ); mTerrainGenerator.reset( gen );
Expand Down
16 changes: 14 additions & 2 deletions src/3d/map3d.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@ class _3D_EXPORT Map3D : public QObject
void setLayers( const QList<QgsMapLayer *> &layers ); void setLayers( const QList<QgsMapLayer *> &layers );
QList<QgsMapLayer *> layers() const; QList<QgsMapLayer *> layers() const;


int tileTextureSize; //!< Size of map textures of tiles in pixels (width/height) void setMapTileResolution( int res );
int maxTerrainError; //!< Maximum allowed terrain error in pixels int mapTileResolution() const;

void setMaxTerrainScreenError( float error );
float maxTerrainScreenError() const;

void setMaxTerrainGroundError( float error );
float maxTerrainGroundError() const;


//! Takes ownership of the generator //! Takes ownership of the generator
void setTerrainGenerator( TerrainGenerator *gen ); void setTerrainGenerator( TerrainGenerator *gen );
Expand All @@ -77,12 +83,18 @@ class _3D_EXPORT Map3D : public QObject
void layersChanged(); void layersChanged();
void terrainGeneratorChanged(); void terrainGeneratorChanged();
void terrainVerticalScaleChanged(); void terrainVerticalScaleChanged();
void mapTileResolutionChanged();
void maxTerrainScreenErrorChanged();
void maxTerrainGroundErrorChanged();
void showTerrainBoundingBoxesChanged(); void showTerrainBoundingBoxesChanged();
void showTerrainTilesInfoChanged(); void showTerrainTilesInfoChanged();


private: private:
double mTerrainVerticalScale; //!< Multiplier of terrain heights to make the terrain shape more pronounced double mTerrainVerticalScale; //!< Multiplier of terrain heights to make the terrain shape more pronounced
std::unique_ptr<TerrainGenerator> mTerrainGenerator; //!< Implementation of the terrain generation std::unique_ptr<TerrainGenerator> mTerrainGenerator; //!< Implementation of the terrain generation
int mMapTileResolution; //!< Size of map textures of tiles in pixels (width/height)
float mMaxTerrainScreenError; //!< Maximum allowed terrain error in pixels (determines when tiles are switched to more detailed ones)
float mMaxTerrainGroundError; //!< Maximum allowed horizontal map error in map units (determines how many zoom levels will be used)
bool mShowTerrainBoundingBoxes; //!< Whether to show bounding boxes of entities - useful for debugging bool mShowTerrainBoundingBoxes; //!< Whether to show bounding boxes of entities - useful for debugging
bool mShowTerrainTileInfo; //!< Whether to draw extra information about terrain tiles to the textures - useful for debugging bool mShowTerrainTileInfo; //!< Whether to draw extra information about terrain tiles to the textures - useful for debugging
QList<QgsMapLayerRef> mLayers; //!< Layers to be rendered QList<QgsMapLayerRef> mLayers; //!< Layers to be rendered
Expand Down
23 changes: 22 additions & 1 deletion src/3d/scene.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <Qt3DExtras/QSkyboxEntity> #include <Qt3DExtras/QSkyboxEntity>
#include <Qt3DLogic/QFrameAction> #include <Qt3DLogic/QFrameAction>


#include <QTimer>

#include "aabb.h" #include "aabb.h"
#include "qgsabstract3drenderer.h" #include "qgsabstract3drenderer.h"
#include "cameracontroller.h" #include "cameracontroller.h"
Expand All @@ -15,6 +17,7 @@
#include "terraingenerator.h" #include "terraingenerator.h"
//#include "testchunkloader.h" //#include "testchunkloader.h"
#include "chunkedentity.h" #include "chunkedentity.h"
#include "utils.h"


#include <Qt3DRender/QMesh> #include <Qt3DRender/QMesh>
#include <Qt3DRender/QSceneLoader> #include <Qt3DRender/QSceneLoader>
Expand Down Expand Up @@ -57,6 +60,9 @@ Scene::Scene( const Map3D &map, Qt3DExtras::QForwardRenderer *defaultFrameGraph,
createTerrain(); createTerrain();
connect( &map, &Map3D::terrainGeneratorChanged, this, &Scene::createTerrain ); connect( &map, &Map3D::terrainGeneratorChanged, this, &Scene::createTerrain );
connect( &map, &Map3D::terrainVerticalScaleChanged, this, &Scene::createTerrain ); connect( &map, &Map3D::terrainVerticalScaleChanged, this, &Scene::createTerrain );
connect( &map, &Map3D::mapTileResolutionChanged, this, &Scene::createTerrain );
connect( &map, &Map3D::maxTerrainScreenErrorChanged, this, &Scene::createTerrain );
connect( &map, &Map3D::maxTerrainGroundErrorChanged, this, &Scene::createTerrain );


// create entities of renderers // create entities of renderers


Expand Down Expand Up @@ -181,7 +187,20 @@ void Scene::createTerrain()
mTerrain = nullptr; mTerrain = nullptr;
} }


mTerrain = new Terrain( 3, mMap ); if ( !mTerrainUpdateScheduled )
{
// defer re-creation of terrain: there may be multiple invokations of this slot, so create the new entity just once
QTimer::singleShot( 0, this, &Scene::createTerrainDeferred );
mTerrainUpdateScheduled = true;
}
}

void Scene::createTerrainDeferred()
{
double tile0width = mMap.terrainGenerator()->extent().width();
int maxZoomLevel = Utils::maxZoomLevel( tile0width, mMap.mapTileResolution(), mMap.maxTerrainGroundError() );

mTerrain = new Terrain( maxZoomLevel, mMap );
//mTerrain->setEnabled(false); //mTerrain->setEnabled(false);
mTerrain->setParent( this ); mTerrain->setParent( this );


Expand All @@ -203,6 +222,8 @@ void Scene::createTerrain()
// add new entity - if any 3D renderer // add new entity - if any 3D renderer
addLayerEntity( layer ); addLayerEntity( layer );
} }

mTerrainUpdateScheduled = false;
} }


void Scene::onLayerRenderer3DChanged() void Scene::onLayerRenderer3DChanged()
Expand Down
2 changes: 2 additions & 0 deletions src/3d/scene.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class _3D_EXPORT Scene : public Qt3DCore::QEntity
void createTerrain(); void createTerrain();
void onLayerRenderer3DChanged(); void onLayerRenderer3DChanged();
void onLayersChanged(); void onLayersChanged();
void createTerrainDeferred();


private: private:
void addLayerEntity( QgsMapLayer *layer ); void addLayerEntity( QgsMapLayer *layer );
Expand All @@ -59,6 +60,7 @@ class _3D_EXPORT Scene : public Qt3DCore::QEntity
QList<ChunkedEntity *> chunkEntities; QList<ChunkedEntity *> chunkEntities;
//! Keeps track of entities that belong to a particular layer //! Keeps track of entities that belong to a particular layer
QMap<QgsMapLayer *, Qt3DCore::QEntity *> mLayerEntities; QMap<QgsMapLayer *, Qt3DCore::QEntity *> mLayerEntities;
bool mTerrainUpdateScheduled = false;
}; };


#endif // SCENE_H #endif // SCENE_H
19 changes: 10 additions & 9 deletions src/3d/terrain/flatterraingenerator.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,22 +13,21 @@
class FlatTerrainChunkLoader : public TerrainChunkLoader class FlatTerrainChunkLoader : public TerrainChunkLoader
{ {
public: public:
FlatTerrainChunkLoader( Terrain *terrain, Qt3DExtras::QPlaneGeometry *tileGeometry, ChunkNode *node ); FlatTerrainChunkLoader( Terrain *terrain, ChunkNode *node );


virtual void load() override; virtual void load() override;
virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent ) override; virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent ) override;


private: private:
Qt3DExtras::QPlaneGeometry *mTileGeometry; Qt3DExtras::QPlaneGeometry *mTileGeometry = nullptr;
}; };




//--------------- //---------------




FlatTerrainChunkLoader::FlatTerrainChunkLoader( Terrain *terrain, Qt3DExtras::QPlaneGeometry *tileGeometry, ChunkNode *node ) FlatTerrainChunkLoader::FlatTerrainChunkLoader( Terrain *terrain, ChunkNode *node )
: TerrainChunkLoader( terrain, node ) : TerrainChunkLoader( terrain, node )
, mTileGeometry( tileGeometry )
{ {
} }


Expand All @@ -43,8 +42,13 @@ Qt3DCore::QEntity *FlatTerrainChunkLoader::createEntity( Qt3DCore::QEntity *pare


// make geometry renderer // make geometry renderer


// simple quad geometry shared by all tiles
// QPlaneGeometry by default is 1x1 with mesh resultion QSize(2,2), centered at 0
// TODO: the geometry could be shared inside Terrain instance (within terrain-generator specific data?)
mTileGeometry = new Qt3DExtras::QPlaneGeometry;

Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer; Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer;
mesh->setGeometry( mTileGeometry ); // does not take ownership - geometry is already owned by FlatTerrain entity mesh->setGeometry( mTileGeometry ); // takes ownership if the component has no parent
entity->addComponent( mesh ); // takes ownership if the component has no parent entity->addComponent( mesh ); // takes ownership if the component has no parent


// create material // create material
Expand Down Expand Up @@ -76,14 +80,11 @@ Qt3DCore::QEntity *FlatTerrainChunkLoader::createEntity( Qt3DCore::QEntity *pare


FlatTerrainGenerator::FlatTerrainGenerator() FlatTerrainGenerator::FlatTerrainGenerator()
{ {
// simple quad geometry shared by all tiles
// QPlaneGeometry by default is 1x1 with mesh resultion QSize(2,2), centered at 0
tileGeometry = new Qt3DExtras::QPlaneGeometry; // TODO: parent to a node...
} }


ChunkLoader *FlatTerrainGenerator::createChunkLoader( ChunkNode *node ) const ChunkLoader *FlatTerrainGenerator::createChunkLoader( ChunkNode *node ) const
{ {
return new FlatTerrainChunkLoader( mTerrain, tileGeometry, node ); return new FlatTerrainChunkLoader( mTerrain, node );
} }


TerrainGenerator *FlatTerrainGenerator::clone() const TerrainGenerator *FlatTerrainGenerator::clone() const
Expand Down
5 changes: 0 additions & 5 deletions src/3d/terrain/flatterraingenerator.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@


#include "chunkloader.h" #include "chunkloader.h"


namespace Qt3DExtras
{
class QPlaneGeometry;
}


class _3D_EXPORT FlatTerrainGenerator : public TerrainGenerator class _3D_EXPORT FlatTerrainGenerator : public TerrainGenerator
{ {
Expand All @@ -34,7 +30,6 @@ class _3D_EXPORT FlatTerrainGenerator : public TerrainGenerator
QgsCoordinateReferenceSystem crs() const { return mCrs; } QgsCoordinateReferenceSystem crs() const { return mCrs; }


private: private:
Qt3DExtras::QPlaneGeometry *tileGeometry;


void updateTilingScheme(); void updateTilingScheme();


Expand Down
2 changes: 1 addition & 1 deletion src/3d/terrain/maptexturegenerator.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ QgsMapSettings MapTextureGenerator::baseMapSettings()
{ {
QgsMapSettings mapSettings; QgsMapSettings mapSettings;
mapSettings.setLayers( map.layers() ); mapSettings.setLayers( map.layers() );
mapSettings.setOutputSize( QSize( map.tileTextureSize, map.tileTextureSize ) ); mapSettings.setOutputSize( QSize( map.mapTileResolution(), map.mapTileResolution() ) );
mapSettings.setDestinationCrs( map.crs ); mapSettings.setDestinationCrs( map.crs );
mapSettings.setBackgroundColor( Qt::gray ); mapSettings.setBackgroundColor( Qt::gray );
return mapSettings; return mapSettings;
Expand Down
2 changes: 1 addition & 1 deletion src/3d/terrain/terrain.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
Terrain::Terrain( int maxLevel, const Map3D &map, Qt3DCore::QNode *parent ) Terrain::Terrain( int maxLevel, const Map3D &map, Qt3DCore::QNode *parent )
: ChunkedEntity( map.terrainGenerator()->rootChunkBbox( map ), : ChunkedEntity( map.terrainGenerator()->rootChunkBbox( map ),
map.terrainGenerator()->rootChunkError( map ), map.terrainGenerator()->rootChunkError( map ),
map.maxTerrainError, maxLevel, map.terrainGenerator(), parent ) map.maxTerrainScreenError(), maxLevel, map.terrainGenerator(), parent )
, map( map ) , map( map )
, mTerrainPicker( nullptr ) , mTerrainPicker( nullptr )
{ {
Expand Down
2 changes: 1 addition & 1 deletion src/3d/terrain/terraingenerator.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ float TerrainGenerator::rootChunkError( const Map3D &map ) const
te = terrainToMapTransform.transformBoundingBox( te ); te = terrainToMapTransform.transformBoundingBox( te );


// use texel size as the error // use texel size as the error
return te.width() / map.tileTextureSize; return te.width() / map.mapTileResolution();
} }


void TerrainGenerator::rootChunkHeightRange( float &hMin, float &hMax ) const void TerrainGenerator::rootChunkHeightRange( float &hMin, float &hMax ) const
Expand Down
13 changes: 13 additions & 0 deletions src/3d/utils.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@






int Utils::maxZoomLevel( double tile0width, double tileResolution, double maxError )
{
if ( maxError <= 0 || tileResolution <= 0 || tile0width <= 0 )
return 0; // invalid input

// derived from:
// tile width [map units] = tile0width / 2^zoomlevel
// tile error [map units] = tile width / tile resolution
// + re-arranging to get zoom level if we know tile error we want to get
double zoomLevel = -log( tileResolution * maxError / tile0width ) / log( 2 );
return round( zoomLevel ); // we could use ceil() here if we wanted to always get to the desired error
}

QString Utils::altClampingToString( AltitudeClamping altClamp ) QString Utils::altClampingToString( AltitudeClamping altClamp )
{ {
switch ( altClamp ) switch ( altClamp )
Expand Down
8 changes: 7 additions & 1 deletion src/3d/utils.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ enum AltitudeBinding
}; };




class Utils class _3D_EXPORT Utils
{ {
public: public:


/**
* Calculates the highest needed zoom level for tiles in quad-tree given width of the base tile (zoom level 0)
* in map units, resolution of the tile (e.g. tile's texture width) and desired maximum error in map units.
*/
static int maxZoomLevel( double tile0width, double tileResolution, double maxError );

static QString altClampingToString( AltitudeClamping altClamp ); static QString altClampingToString( AltitudeClamping altClamp );
static AltitudeClamping altClampingFromString( const QString &str ); static AltitudeClamping altClampingFromString( const QString &str );


Expand Down
Loading

0 comments on commit 905222d

Please sign in to comment.