Skip to content
Permalink
Browse files

Got the scene to export using a selected level of details

  • Loading branch information
NEDJIMAbelgacem committed Jul 3, 2020
1 parent f3282e5 commit 14881ce1038004d06fbbae5157415b5251e065e4
@@ -766,10 +766,11 @@ void Qgs3DMapScene::updateSceneState()
setSceneState( Ready );
}

void Qgs3DMapScene::exportScene( const QString &sceneName, const QString &sceneDir, bool smoothEdges )
void Qgs3DMapScene::exportScene( const QString &sceneName, const QString &sceneDir, int levelOfDetails, bool smoothEdges )
{
Qgs3DSceneExporter exporter;

exporter.setLevelOfDetails( levelOfDetails );
exporter.setSmoothEdges( smoothEdges );

for ( QgsMapLayer *layer : mLayerEntities.keys() )
@@ -102,7 +102,7 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
*/
float worldSpaceError( float epsilon, float distance );

void exportScene( const QString &sceneName, const QString &sceneDir, bool smoothEdges = false );
void exportScene( const QString &sceneName, const QString &sceneDir, int levelOfDetails = 1, bool smoothEdges = false );
signals:
//! Emitted when the current terrain entity is replaced by a new one
void terrainEntityChanged();
@@ -163,9 +163,12 @@ QVector<int> createPlaneIndexData( const QSize &resolution )
return indexes;
}

Qgs3DSceneExporter::Qgs3DSceneExporter( )
: mVertxPosition()
Qgs3DSceneExporter::Qgs3DSceneExporter( Qt3DCore::QNode *parent )
: Qt3DCore::QEntity( parent )
, mVertxPosition()
, mIndexes()
, mSmoothEdges( false )
, mLevelOfDetails( 1 )
{

}
@@ -213,14 +216,45 @@ void Qgs3DSceneExporter::parseEntity( Qt3DCore::QEntity *entity )
void Qgs3DSceneExporter::parseEntity( QgsTerrainEntity *terrain )
{
QgsChunkNode *root = terrain->rootNode();

int levelOfDetails = mLevelOfDetails;
QVector<QgsChunkNode *> leafs;
leafs << root;
for ( int i = 0; i < levelOfDetails; ++i )
{
QVector<QgsChunkNode *> nodes = leafs;
leafs.clear();
for ( QgsChunkNode *node : nodes )
{
node->ensureAllChildrenExist();
QgsChunkNode *const *children = node->children();
for ( int i = 0; i < 4; ++i )
{
if ( children[i] != nullptr )
{
leafs.push_back( children[i] );
}
}
}
}

QgsTerrainGenerator *generator = terrain->map3D().terrainGenerator();
QgsTerrainTileEntity *terrainTile = nullptr;
switch ( generator->type() )
{
case QgsTerrainGenerator::Dem:
generateDemTerrain( terrain, root );
for ( QgsChunkNode *node : leafs )
{
terrainTile = getDemTerrainEntity( terrain, node );
this->parseDemTile( terrainTile );
}
break;
case QgsTerrainGenerator::Flat:
generateFlatTerrain( terrain, root );
for ( QgsChunkNode *node : leafs )
{
terrainTile = getFlatTerrainEntity( terrain, node );
this->parseFlatTile( terrainTile );
}
break;
// TODO: implement other terrain types
case QgsTerrainGenerator::Mesh:
@@ -230,16 +264,33 @@ void Qgs3DSceneExporter::parseEntity( QgsTerrainEntity *terrain )
}
}

void Qgs3DSceneExporter::generateFlatTerrain( QgsTerrainEntity *terrain, QgsChunkNode *node )
QgsTerrainTileEntity *Qgs3DSceneExporter::getFlatTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
{
QgsFlatTerrainGenerator *generator = dynamic_cast<QgsFlatTerrainGenerator *>( terrain->map3D().terrainGenerator() );
QgsChunkLoader *loader = generator->createChunkLoader( node );
FlatTerrainChunkLoader *floatTerrainLoader = qobject_cast<FlatTerrainChunkLoader *>( loader );
if ( floatTerrainLoader == nullptr ) return;
Qt3DCore::QEntity *entity = floatTerrainLoader->createEntity( nullptr );
FlatTerrainChunkLoader *flatTerrainLoader = qobject_cast<FlatTerrainChunkLoader *>( loader );
if ( flatTerrainLoader == nullptr ) return nullptr;
// the entity we created should be deallocated when we deallocate the scene exporter
Qt3DCore::QEntity *entity = flatTerrainLoader->createEntity( this );
QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
if ( tileEntity != nullptr ) parseFlatTile( tileEntity );
if ( entity != nullptr ) delete entity;
return tileEntity;
}

QgsTerrainTileEntity *Qgs3DSceneExporter::getDemTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
{
QgsTerrainTileEntity *tileEntity = nullptr;
if ( node->entity() != nullptr )
{
// read tile data as displayed in the scene (no need to make the entity)
Qt3DCore::QEntity *entity = node->entity();
tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
}
else
{
// create the entity synchronously and then it will be deleted once our scene exporter instance is deallocated
tileEntity = createDEMTileEntity( terrain, node );
}
return tileEntity;
}

static void _heightMapMinMax( const QByteArray &heightMap, float &zMin, float &zMax )
@@ -313,40 +364,12 @@ QgsTerrainTileEntity *Qgs3DSceneExporter::createDEMTileEntity( QgsTerrainEntity
// node->setExactBbox( QgsAABB( x0, zMin * map.terrainVerticalScale(), -y0, x0 + side, zMax * map.terrainVerticalScale(), -( y0 + side ) ) );

entity->setEnabled( false );
// entity->setParent( nullptr );
// set the parent to our scene exporter class so it will be deallocated properly
entity->setParent( this );

return entity;
}

void Qgs3DSceneExporter::generateDemTerrain( QgsTerrainEntity *terrain, QgsChunkNode *node )
{
QgsChunkNode *const *children = node->children();
bool isLeaf = true;
for ( int i = 0; i < 4; ++i )
{
if ( children[i] == nullptr ) continue;
generateDemTerrain( terrain, children[i] );
isLeaf = false;
}
if ( !isLeaf ) return;

if ( node->entity() != nullptr )
{
// read tile data as displayed in the scene
Qt3DCore::QEntity *entity = node->entity();
qDebug() << "Loading existing entity";
QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
if ( tileEntity != nullptr ) parseDemTile( tileEntity );
}
else
{
// create the entity synchronously and then delete it
QgsTerrainTileEntity *entity = createDEMTileEntity( terrain, node );
if ( entity != nullptr ) parseDemTile( entity );
if ( entity != nullptr ) delete entity;
}
}

void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity )
{
qDebug() << "Parsing Terrain tile entity";
@@ -517,7 +540,7 @@ void Qgs3DSceneExporter::saveToFile( const QString &filePath )

qDebug() << "Vertical span : " << diffY;

float scale = diffY;//qMax( diffX, qMax( diffY, diffZ ) );
float scale = std::max( diffX, std::max( diffY, diffZ ) );

QTextStream out( &file );

@@ -29,11 +29,11 @@ class QgsFlatTerrainGenerator;
class QgsDemTerrainGenerator;
class QgsChunkNode;

class Qgs3DSceneExporter
class Qgs3DSceneExporter : public Qt3DCore::QEntity
{

Q_OBJECT
public:
Qgs3DSceneExporter( );
Qgs3DSceneExporter( Qt3DCore::QNode *parent = nullptr );

void parseEntity( Qt3DCore::QEntity *entity );
void parseEntity( QgsTerrainEntity *terrain );
@@ -42,24 +42,27 @@ class Qgs3DSceneExporter
void setSmoothEdges( bool smoothEdges ) { mSmoothEdges = smoothEdges; }
bool smoothEdges() { return mSmoothEdges; }

void setLevelOfDetails( int levelOfDetails ) { mLevelOfDetails = levelOfDetails; }
int levelOfDetails() { return mLevelOfDetails; }

private:
void processAttribute( Qt3DRender::QAttribute *attribute );
void process( QgsTessellatedPolygonGeometry *geom );
void process( Qt3DExtras::QPlaneGeometry *plane );

void generateFlatTerrain( QgsTerrainEntity *terrain, QgsChunkNode *node );
void generateDemTerrain( QgsTerrainEntity *terrain, QgsChunkNode *node );
QgsTerrainTileEntity *getFlatTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node );
QgsTerrainTileEntity *getDemTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node );

void parseDemTile( QgsTerrainTileEntity *tileEntity );
void parseFlatTile( QgsTerrainTileEntity *tileEntity );

QgsTerrainTileEntity *createDEMTileEntity( QgsTerrainEntity *terrain, QgsChunkNode *node );
private:
bool mSmoothEdges = false;

QVector<float> mVertxPosition;
QVector<int> mIndexes;
QMap<int, QString> mComments;

bool mSmoothEdges;
int mLevelOfDetails;
};

#endif // QGS3DSCENEEXPORTER_H
@@ -1,3 +1,18 @@
/***************************************************************************
qgsmap3dexportwidget.cpp
--------------------------------------
Date : July 2020
Copyright : (C) 2020 by Belgacem Nedjima
Email : gb underscore nedjima at esi dot dz
***************************************************************************
* *
* 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 "qgsmap3dexportwidget.h"
#include "ui_map3dexportwidget.h"

@@ -7,29 +22,37 @@
#include "qgs3dmapscene.h"
#include "qgssettings.h"

QgsMap3DExportWidget::QgsMap3DExportWidget(Qgs3DMapScene* scene, QWidget *parent) :
QWidget(parent),
ui(new Ui::Map3DExportWidget),
mScene(scene)
QgsMap3DExportWidget::QgsMap3DExportWidget( Qgs3DMapScene *scene, QWidget *parent ) :
QWidget( parent ),
ui( new Ui::Map3DExportWidget ),
mScene( scene )
{
ui->setupUi(this);

connect(ui->selectFolderBtn, &QPushButton::clicked, [=](bool ) {
QgsSettings settings; // where we keep last used filter in persistent state
QString initialPath = settings.value( QStringLiteral( "UI/lastExportAsDir" ), QDir::homePath() ).toString();
QString outputDir = QFileDialog::getExistingDirectory(this, QString("Export scane"), initialPath);
ui->folderNameLineEdit->setText(outputDir);
});
ui->setupUi( this );

QgsSettings settings;
QString initialPath = settings.value( QStringLiteral( "UI/last3DSceneExportDir" ), QDir::homePath() ).toString();
ui->folderPathLineEdit->setText( initialPath );

connect( ui->selectFolderBtn, &QPushButton::clicked, [ = ]( bool )
{
QString initialPath = ui->folderPathLineEdit->text();
QString outputDir = QFileDialog::getExistingDirectory( this, QString( "Export scane" ), initialPath );
ui->folderPathLineEdit->setText( outputDir );
} );
}

QgsMap3DExportWidget::~QgsMap3DExportWidget()
{
delete ui;
}

void QgsMap3DExportWidget::exportScene() {
void QgsMap3DExportWidget::exportScene()
{
QString sceneName = ui->sceneNameLineEdit->text();
QString sceneFolder = ui->folderNameLineEdit->text();
QString sceneFolder = ui->folderPathLineEdit->text();
int levelOfDetails = ui->levelOfDetailsSpinBox->value();
bool smoothEdges = ui->smoothEdgesCheckBox->isChecked();
mScene->exportScene(sceneName, sceneFolder, smoothEdges);
mScene->exportScene( sceneName, sceneFolder, levelOfDetails, smoothEdges );
QgsSettings settings;
settings.setValue( QStringLiteral( "UI/last3DSceneExportDir" ), sceneFolder );
}
@@ -1,10 +1,26 @@
/***************************************************************************
qgsmap3dexportwidget.h
--------------------------------------
Date : July 2020
Copyright : (C) 2020 by Belgacem Nedjima
Email : gb underscore nedjima at esi dot dz
***************************************************************************
* *
* 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 QGSMAP3DEXPORTWIDGET_H
#define QGSMAP3DEXPORTWIDGET_H

#include <QWidget>

namespace Ui {
class Map3DExportWidget;
namespace Ui
{
class Map3DExportWidget;
}

class Qgs3DMapScene;
@@ -14,14 +30,14 @@ class QgsMap3DExportWidget : public QWidget
Q_OBJECT

public:
explicit QgsMap3DExportWidget(Qgs3DMapScene* scene, QWidget *parent = nullptr);
explicit QgsMap3DExportWidget( Qgs3DMapScene *scene, QWidget *parent = nullptr );
~QgsMap3DExportWidget();

void exportScene();
private:
Ui::Map3DExportWidget *ui;
private:
Qgs3DMapScene* mScene = nullptr;
Qgs3DMapScene *mScene = nullptr;
};

#endif // QGSMAP3DEXPORTWIDGET_H

0 comments on commit 14881ce

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