Skip to content
Permalink
Browse files

Initial work on integration of 3D map into QGIS application

One can create a 3D map view from menu similar to a new 3D map view
  • Loading branch information
wonder-sk committed Jul 23, 2017
1 parent 8f76477 commit 0469d443011edea9850ce63ea2bb417201da95b0
@@ -217,6 +217,13 @@ void CameraController::frameTriggered( float dt )
}
}

void CameraController::resetView()
{
setCameraData( 0, 0, 1000 );

emit cameraChanged();
}

void CameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
{
mMousePos = QPoint( mouse->x(), mouse->y() );
@@ -27,6 +27,9 @@ class _3D_EXPORT CameraController : public Qt3DCore::QEntity

void frameTriggered( float dt );

//! Move camera back to the initial position (looking down towards origin of world's coordinates)
void resetView();

signals:
void cameraChanged();
void viewportChanged();
@@ -86,6 +86,10 @@ Map3D::Map3D()
{
}

Map3D::~Map3D()
{
}

void Map3D::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
Q_UNUSED( context );
@@ -151,6 +151,7 @@ class _3D_EXPORT Map3D
{
public:
Map3D();
~Map3D();

void readXml( const QDomElement &elem, const QgsReadWriteContext &context );

@@ -45,7 +45,7 @@ Scene::Scene( const Map3D &map, Qt3DExtras::QForwardRenderer *defaultFrameGraph,
mCameraController = new CameraController( this ); // attaches to the scene
mCameraController->setViewport( viewportRect );
mCameraController->setCamera( camera );
mCameraController->setCameraData( 0, 0, 1000 );
mCameraController->resetView();

// create terrain entity
mTerrain = new Terrain( 3, map );
@@ -1,5 +1,6 @@
#include "maptexturegenerator.h"

#include <qgsmaprenderercustompainterjob.h>
#include <qgsmaprenderersequentialjob.h>
#include <qgsmapsettings.h>
#include <qgsproject.h>
@@ -54,22 +55,26 @@ QImage MapTextureGenerator::renderSynchronously( const QgsRectangle &extent, con
QgsMapSettings mapSettings( baseMapSettings() );
mapSettings.setExtent( extent );

QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();
QImage img = QImage( mapSettings.outputSize(), mapSettings.outputImageFormat() );
img.setDotsPerMeterX( 1000 * mapSettings.outputDpi() / 25.4 );
img.setDotsPerMeterY( 1000 * mapSettings.outputDpi() / 25.4 );
img.fill( Qt::transparent );

QImage img = job.renderedImage();
QPainter p( &img );

QgsMapRendererCustomPainterJob job( mapSettings, &p );
job.renderSynchronously();

if ( !debugText.isEmpty() )
{
// extra tile information for debugging
QPainter p( &img );
p.setPen( Qt::white );
p.drawRect( 0, 0, img.width() - 1, img.height() - 1 );
p.drawText( img.rect(), debugText, QTextOption( Qt::AlignCenter ) );
p.end();
}

p.end();

return img;
}

@@ -0,0 +1,57 @@
#include "qgs3dmapcanvas.h"

#include <QBoxLayout>
#include <Qt3DExtras/Qt3DWindow>

#include "cameracontroller.h"
#include "map3d.h"
#include "scene.h"


Qgs3DMapCanvas::Qgs3DMapCanvas( QWidget *parent )
: QWidget( parent )
, mWindow3D( nullptr )
, mContainer( nullptr )
, mMap( nullptr )
, mScene( nullptr )
{
mWindow3D = new Qt3DExtras::Qt3DWindow;
mContainer = QWidget::createWindowContainer( mWindow3D );

QHBoxLayout *hLayout = new QHBoxLayout( this );
hLayout->setMargin( 0 );
hLayout->addWidget( mContainer, 1 );
}

Qgs3DMapCanvas::~Qgs3DMapCanvas()
{
delete mMap;
}

void Qgs3DMapCanvas::resizeEvent( QResizeEvent *ev )
{
QWidget::resizeEvent( ev );

QRect viewportRect( QPoint( 0, 0 ), size() );
mScene->cameraController()->setViewport( viewportRect );
}

void Qgs3DMapCanvas::setMap( Map3D *map )
{
QRect viewportRect( QPoint( 0, 0 ), size() );
Scene *newScene = new Scene( *map, mWindow3D->defaultFrameGraph(), mWindow3D->renderSettings(), mWindow3D->camera(), viewportRect );

mWindow3D->setRootEntity( newScene );

if ( mScene )
mScene->deleteLater();
mScene = newScene;

delete mMap;
mMap = map;
}

void Qgs3DMapCanvas::resetView()
{
mScene->cameraController()->resetView();
}
@@ -0,0 +1,42 @@
#ifndef QGS3DMAPWIDGET_H
#define QGS3DMAPWIDGET_H

#include <QWidget>

namespace Qt3DExtras
{
class Qt3DWindow;
}

class Map3D;
class Scene;


class Qgs3DMapCanvas : public QWidget
{
Q_OBJECT
public:
Qgs3DMapCanvas( QWidget *parent = nullptr );
~Qgs3DMapCanvas();

//! Configure map scene being displayed. Takes ownership.
void setMap( Map3D *map );

//! Resets camera position to the default: looking down at the origin of world coordinates
void resetView();

protected:
void resizeEvent( QResizeEvent *ev ) override;

private:
//! 3D window with all the 3D magic inside
Qt3DExtras::Qt3DWindow *mWindow3D;
//! Container QWidget that encapsulates mWindow3D so we can use it embedded in ordinary widgets app
QWidget *mContainer;
//! Description of the 3D scene
Map3D *mMap;
//! Root entity of the 3D scene
Scene *mScene;
};

#endif // QGS3DMAPWIDGET_H
@@ -0,0 +1,36 @@
#include "qgs3dmapcanvasdockwidget.h"

#include "qgs3dmapcanvas.h"

#include <QBoxLayout>
#include <QToolBar>

Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
: QgsDockWidget( parent )
{
QWidget *contentsWidget = new QWidget( this );

QToolBar *toolBar = new QToolBar( contentsWidget );
toolBar->addAction( "Reset view", this, &Qgs3DMapCanvasDockWidget::resetView );

mCanvas = new Qgs3DMapCanvas( contentsWidget );
mCanvas->setMinimumSize( QSize( 200, 200 ) );

QVBoxLayout *layout = new QVBoxLayout( contentsWidget );
layout->setContentsMargins( 0, 0, 0, 0 );
layout->setSpacing( 0 );
layout->addWidget( toolBar );
layout->addWidget( mCanvas, 1 );

setWidget( contentsWidget );
}

void Qgs3DMapCanvasDockWidget::setMap( Map3D *map )
{
mCanvas->setMap( map );
}

void Qgs3DMapCanvasDockWidget::resetView()
{
mCanvas->resetView();
}
@@ -0,0 +1,27 @@
#ifndef QGS3DMAPCANVASDOCKWIDGET_H
#define QGS3DMAPCANVASDOCKWIDGET_H

#include "qgsdockwidget.h"

class Qgs3DMapCanvas;

class Map3D;


class Qgs3DMapCanvasDockWidget : public QgsDockWidget
{
Q_OBJECT
public:
Qgs3DMapCanvasDockWidget( QWidget *parent = nullptr );

//! takes ownership
void setMap( Map3D *map );

private slots:
void resetView();

private:
Qgs3DMapCanvas *mCanvas;
};

#endif // QGS3DMAPCANVASDOCKWIDGET_H
@@ -363,6 +363,22 @@ SET (QGIS_APP_MOC_HDRS
qgscrashdialog.h
)


IF (WITH_3D)
SET(QGIS_APP_SRCS
${QGIS_APP_SRCS}
3d/qgs3dmapcanvas.cpp
3d/qgs3dmapcanvasdockwidget.cpp
)

SET (QGIS_APP_MOC_HDRS
${QGIS_APP_MOC_HDRS}
3d/qgs3dmapcanvas.h
3d/qgs3dmapcanvasdockwidget.h
)
ENDIF (WITH_3D)


SET (WITH_QWTPOLAR FALSE CACHE BOOL "Determines whether QwtPolar should be built")

IF (WITH_QWTPOLAR)
@@ -540,6 +556,16 @@ INCLUDE_DIRECTORIES(
${CMAKE_BINARY_DIR}/src/native
)

IF (WITH_3D)
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/src/app/3d
${CMAKE_SOURCE_DIR}/src/3d
${CMAKE_SOURCE_DIR}/src/3d/terrain
${CMAKE_SOURCE_DIR}/src/3d/chunks
${CMAKE_BINARY_DIR}/src/3d
)
ENDIF (WITH_3D)

INCLUDE_DIRECTORIES(SYSTEM
${QWT_INCLUDE_DIR}
${QT_QTUITOOLS_INCLUDE_DIR}
@@ -637,6 +663,12 @@ TARGET_LINK_LIBRARIES(qgis_app
libdxfrw
)

IF (WITH_3D)
TARGET_LINK_LIBRARIES(qgis_app
qgis_3d
)
ENDIF (WITH_3D)

GENERATE_EXPORT_HEADER(
qgis_app
BASE_NAME APP
@@ -1709,6 +1709,7 @@ void QgisApp::createActions()
connect( mActionSaveMapAsImage, &QAction::triggered, this, [ = ] { saveMapAsImage(); } );
connect( mActionSaveMapAsPdf, &QAction::triggered, this, [ = ] { saveMapAsPdf(); } );
connect( mActionNewMapCanvas, &QAction::triggered, this, &QgisApp::newMapCanvas );
connect( mActionNew3DMapCanvas, &QAction::triggered, this, &QgisApp::new3DMapCanvas );
connect( mActionNewPrintComposer, &QAction::triggered, this, &QgisApp::newPrintComposer );
connect( mActionShowComposerManager, &QAction::triggered, this, &QgisApp::showComposerManager );
connect( mActionExit, &QAction::triggered, this, &QgisApp::fileExit );
@@ -9878,6 +9879,39 @@ void QgisApp::newMapCanvas()
}
}

#include "qgs3dmapcanvasdockwidget.h"
#include "map3d.h"
#include "flatterraingenerator.h"

void QgisApp::new3DMapCanvas()
{
// initialize from project
QgsProject *prj = QgsProject::instance();
QgsRectangle fullExtent = mMapCanvas->fullExtent();

Map3D *map = new Map3D;
map->showBoundingBoxes = true;
map->drawTerrainTileInfo = true;
map->crs = prj->crs();
map->originX = fullExtent.center().x();
map->originY = fullExtent.center().y();
map->backgroundColor = mMapCanvas->canvasColor();
map->setLayers( mMapCanvas->layers() );

FlatTerrainGenerator *flatTerrain = new FlatTerrainGenerator;
flatTerrain->setCrs( map->crs );
flatTerrain->setExtent( fullExtent );
map->terrainGenerator.reset( flatTerrain );

// TODO: combine with code in createNewMapCanvasDock()
Qgs3DMapCanvasDockWidget *map3DWidget = new Qgs3DMapCanvasDockWidget( this );
map3DWidget->setWindowTitle( "Super 3D Map Widget" );
map3DWidget->setAllowedAreas( Qt::AllDockWidgetAreas );
map3DWidget->setGeometry( QRect( rect().width() * 0.75, rect().height() * 0.5, 400, 400 ) );
map3DWidget->setMap( map );
addDockWidget( Qt::RightDockWidgetArea, map3DWidget );
}

void QgisApp::setExtent( const QgsRectangle &rect )
{
mMapCanvas->setExtent( rect );
@@ -1157,6 +1157,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow

//! Creates a new map canvas view
void newMapCanvas();
//! Creates a new 3D map canvas view
void new3DMapCanvas();

//! Create a new empty vector layer
void newVectorLayer();

0 comments on commit 0469d44

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