Skip to content
Permalink
Browse files

Add 3D map print layout item

So far this is just support in the layout framework, not yet exposed to the GUI.
  • Loading branch information
wonder-sk committed Aug 21, 2018
1 parent 9fbef83 commit 2e56fadcd1f171f9c44a4b3ecfc4622984c81e85
@@ -178,6 +178,8 @@ of layout items.
LayoutAttributeTable,
LayoutTextTable,

Layout3DMap,

// item
PluginItem,
};
@@ -9,6 +9,7 @@ SET(QGIS_3D_SRCS
qgs3dutils.cpp
qgscameracontroller.cpp
qgscamerapose.cpp
qgslayoutitem3dmap.cpp
qgsoffscreen3dengine.cpp
qgsphongmaterialsettings.cpp
qgsraycastingutils_p.cpp
@@ -83,6 +84,7 @@ SET(QGIS_3D_HDRS
qgs3dutils.h
qgscameracontroller.h
qgscamerapose.h
qgslayoutitem3dmap.h
qgsoffscreen3dengine.h
qgsphongmaterialsettings.h
qgsraycastingutils_p.h
@@ -131,6 +133,7 @@ INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/src/core/symbology
${CMAKE_SOURCE_DIR}/src/core/metadata
${CMAKE_SOURCE_DIR}/src/core/expression
${CMAKE_SOURCE_DIR}/src/core/layout
${CMAKE_SOURCE_DIR}/src/core/3d
${CMAKE_BINARY_DIR}/src/core
${CMAKE_BINARY_DIR}/src/3d
@@ -0,0 +1,67 @@
/***************************************************************************
qgslayoutitem3dmap.cpp
--------------------------------------
Date : August 2018
Copyright : (C) 2018 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 "qgslayoutitem3dmap.h"

#include "qgs3dmapscene.h"
#include "qgs3dutils.h"
#include "qgscameracontroller.h"
#include "qgslayout.h"
#include "qgslayoutitemregistry.h"
#include "qgsoffscreen3dengine.h"


QgsLayoutItem3DMap::QgsLayoutItem3DMap( QgsLayout *layout )
: QgsLayoutItem( layout )
{

}

QgsLayoutItem3DMap *QgsLayoutItem3DMap::create( QgsLayout *layout )
{
return new QgsLayoutItem3DMap( layout );
}

int QgsLayoutItem3DMap::type() const
{
return QgsLayoutItemRegistry::Layout3DMap;
}

void QgsLayoutItem3DMap::draw( QgsLayoutItemRenderContext &context )
{
QgsOffscreen3DEngine engine;
QSizeF sizePixels = mLayout->renderContext().measurementConverter().convert( sizeWithUnits(), QgsUnitTypes::LayoutPixels ).toQSizeF();
engine.setSize( QSize( qCeil( sizePixels.width() ), qCeil( sizePixels.height() ) ) );

Qgs3DMapScene *scene = new Qgs3DMapScene( *mSettings, &engine );
engine.setRootEntity( scene );

scene->cameraController()->setCameraPose( mCameraPose );

// XXX this should not be needed, but without it the scene often
// is not completely ready (e.g. a missing terrain tile).
// leaving it here until a more robust solution is found...
Qgs3DUtils::captureSceneImage( engine, scene );

QImage img = Qgs3DUtils::captureSceneImage( engine, scene );

QgsRenderContext &ctx = context.renderContext();
ctx.painter()->drawImage( 0, 0, img );
}

void QgsLayoutItem3DMap::setMapSettings( Qgs3DMapSettings *settings )
{
mSettings.reset( settings );
}
@@ -0,0 +1,94 @@
/***************************************************************************
qgslayoutitem3dmap.h
--------------------------------------
Date : August 2018
Copyright : (C) 2018 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 QGSLAYOUTITEM3DMAP_H
#define QGSLAYOUTITEM3DMAP_H

#include "qgis_3d.h"

#include "qgslayoutitem.h"

#include "qgscamerapose.h"


class Qgs3DMapSettings;

/**
* \ingroup 3d
*
* Implements support of 3D map views in print layouts
*
* \since QGIS 3.4
*/
class _3D_EXPORT QgsLayoutItem3DMap : public QgsLayoutItem
{

#ifdef SIP_RUN
SIP_CONVERT_TO_SUBCLASS_CODE
// the conversions have to be static, because they're using multiple inheritance
// (seen in PyQt4 .sip files for some QGraphicsItem classes)
switch ( sipCpp->type() )
{
// really, these *should* use the constants from QgsLayoutItemRegistry, but sip doesn't like that!
case QGraphicsItem::UserType + 115:
sipType = sipType_QgsLayoutItem3DMap;
*sipCppRet = static_cast<QgsLayoutItem3DMap *>( sipCpp );
break;
default:
sipType = 0;
}
SIP_END
#endif

public:

/**
* Constructor for QgsLayoutItem3DMap, with the specified parent \a layout.
*
* Ownership is transferred to the layout.
*/
QgsLayoutItem3DMap( QgsLayout *layout SIP_TRANSFERTHIS );

/**
* Returns a new 3D map item for the specified \a layout.
*
* The caller takes responsibility for deleting the returned object.
*/
static QgsLayoutItem3DMap *create( QgsLayout *layout ) SIP_FACTORY;

virtual int type() const override;

virtual void draw( QgsLayoutItemRenderContext &context ) override;

//! Configures camera view
void setCameraPose( const QgsCameraPose &pose ) { mCameraPose = pose; }
//! Returns camera view
QgsCameraPose cameraPose() const { return mCameraPose; }

/**
* Configures map scene
*
* Ownership is transferred to the item.
*/
void setMapSettings( Qgs3DMapSettings *settings SIP_TRANSFER );
//! Returns map scene. May be a null pointer if not yet configured.
Qgs3DMapSettings *mapSettings() const { return mSettings.get(); }

private:
std::unique_ptr<Qgs3DMapSettings> mSettings;
QgsCameraPose mCameraPose;
};

#endif // QGSLAYOUTITEM3DMAP_H
@@ -90,6 +90,7 @@
#include "qgs3dmapsettings.h"
#include "qgscameracontroller.h"
#include "qgsflatterraingenerator.h"
#include "qgslayoutitem3dmap.h"
#include "qgsvectorlayer3drenderer.h"
#include "processing/qgs3dalgorithms.h"
#endif
@@ -10798,6 +10799,12 @@ void QgisApp::initNativeProcessing()

void QgisApp::initLayouts()
{
#ifdef HAVE_3D
QgsApplication::layoutItemRegistry()->addLayoutItemType(
new QgsLayoutItemMetadata( QgsLayoutItemRegistry::Layout3DMap, QObject::tr( "3D Map" ), QgsLayoutItem3DMap::create )
);
#endif

QgsLayoutAppUtils::registerGuiForKnownItemTypes();

mLayoutQptDropHandler = new QgsLayoutQptDropHandler( this );
@@ -183,6 +183,7 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
SIP_END
#endif


Q_OBJECT
Q_PROPERTY( bool locked READ isLocked WRITE setLocked NOTIFY lockChanged )

@@ -320,6 +320,8 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
LayoutAttributeTable, //!< Attribute table
LayoutTextTable, //!< Preset text table

Layout3DMap, //!< 3D map item

// item types provided by plugins
PluginItem = LayoutTextTable + 10000, //!< Starting point for plugin item types
};
@@ -71,4 +71,5 @@ ENDMACRO (ADD_QGIS_TEST)

ADD_QGIS_TEST(3dutilstest testqgs3dutils.cpp)
ADD_QGIS_TEST(3drenderingtest testqgs3drendering.cpp)
ADD_QGIS_TEST(layout3dmaptest testqgslayout3dmap.cpp)
ADD_QGIS_TEST(tessellatortest testqgstessellator.cpp)
@@ -0,0 +1,130 @@
/***************************************************************************
testqgslayout3dmap.cpp
-----------------------
begin : August 2018
copyright : (C) 2018 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 "qgs3dmapsettings.h"
#include "qgsapplication.h"
#include "qgsflatterraingenerator.h"
#include "qgslayoutframe.h"
#include "qgslayoutitem3dmap.h"
#include "qgslayout.h"
#include "qgsmultirenderchecker.h"
#include "qgsfontutils.h"
#include "qgsproject.h"
#include "qgsrasterlayer.h"

#include <QObject>
#include "qgstest.h"

class TestQgsLayout3DMap : public QObject
{
Q_OBJECT

private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.

void testBasic();

private:
QString mReport;
QFont mTestFont;
std::unique_ptr<QgsProject> mProject;
QgsRasterLayer *mLayerDtm;
};

void TestQgsLayout3DMap::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();

mProject.reset( new QgsProject );

QString dataDir( TEST_DATA_DIR );
mLayerDtm = new QgsRasterLayer( dataDir + "/3d/dtm.tif", "rgb", "gdal" );
QVERIFY( mLayerDtm->isValid() );
mProject->addMapLayer( mLayerDtm );

mProject->setCrs( mLayerDtm->crs() );

mReport = QStringLiteral( "<h1>Layout 3D Map Tests</h1>\n" );

QgsFontUtils::loadStandardTestFonts( QStringList() << QStringLiteral( "Oblique" ) );
mTestFont = QgsFontUtils::getStandardTestFont( QStringLiteral( "Oblique " ) );
}

void TestQgsLayout3DMap::cleanupTestCase()
{
mProject.reset();

QString myReportFile = QDir::tempPath() + "/qgistest.html";
QFile myFile( myReportFile );
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
{
QTextStream myQTextStream( &myFile );
myQTextStream << mReport;
myFile.close();
}
QgsApplication::exitQgis();
}

void TestQgsLayout3DMap::init()
{

}

void TestQgsLayout3DMap::cleanup()
{

}

void TestQgsLayout3DMap::testBasic()
{
QgsRectangle fullExtent = mLayerDtm->extent();

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setLayers( QList<QgsMapLayer *>() << mLayerDtm );

QgsFlatTerrainGenerator *flatTerrain = new QgsFlatTerrainGenerator;
flatTerrain->setCrs( map->crs() );
flatTerrain->setExtent( fullExtent );
map->setTerrainGenerator( flatTerrain );

QgsCameraPose cam;
cam.setDistanceFromCenterPoint( 2500 );

QgsLayout l( mProject.get() );
l.initializeDefaults();

QgsLayoutItem3DMap *map3dItem = new QgsLayoutItem3DMap( &l );
map3dItem->attemptSetSceneRect( QRectF( 0, 0, 297, 210 ) );
map3dItem->setCameraPose( cam );
map3dItem->setMapSettings( map );
l.addLayoutItem( map3dItem );

QgsLayoutChecker checker( QStringLiteral( "composer3d_basic" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_3d" ) );
bool result = checker.testLayout( mReport, 0, 100 );
QVERIFY( result );
}


QGSTEST_MAIN( TestQgsLayout3DMap )
#include "testqgslayout3dmap.moc"
Binary file not shown.

0 comments on commit 2e56fad

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