Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Vector tile layer - part 1 #35341

Merged
merged 27 commits into from
Apr 2, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8105ad1
Initial work on vector tile layer support
wonder-sk Mar 25, 2020
da57d93
Added two new forgotten files with QgsTileXYZ, QgsTileMatrx, QgsTileR…
wonder-sk Mar 26, 2020
bbc6af5
Fixes to python bindings + some bits from code review
wonder-sk Mar 26, 2020
617db59
Doxygen, spelling, sip fixes
wonder-sk Mar 26, 2020
f43bd8c
Move the generated code for MVT to a directory in external/
wonder-sk Mar 26, 2020
976c0e0
Do not mix class and struct
wonder-sk Mar 26, 2020
4b362b3
Silence warning, avoid indentation on generated MVT files
wonder-sk Mar 26, 2020
5ec1890
Moved to proper QgsMapLayer subclass + icon + optional tile borders
wonder-sk Mar 27, 2020
b590aae
Added forgotten icon for vector tile layer
wonder-sk Mar 27, 2020
8d24e17
Added zmin/zmax parameters to limit usable zoom levels
wonder-sk Mar 27, 2020
6a107c8
Added initial unit test + test data
wonder-sk Mar 27, 2020
3c33bf7
Added a basic rendering test
wonder-sk Mar 27, 2020
9e80f59
Use random colors, fix sip includes, fix warnings in server
wonder-sk Mar 27, 2020
4744777
Handle on-the-fly reprojection correctly
wonder-sk Mar 27, 2020
804ac87
Get rid of qDebug(), wrap strings in QStringLiteral
wonder-sk Mar 27, 2020
81a7af7
Updates from review (debug msg level 2, qBound, wider lines for test)
wonder-sk Mar 28, 2020
4e7809c
Update src/gui/qgsbrowserdockwidget_p.cpp
wonder-sk Mar 28, 2020
8c90de9
Dummy commit to trigger new azure build (PR reopen does nothing)
wonder-sk Mar 30, 2020
93715f7
Do not use pre-generated files from protoc
wonder-sk Mar 30, 2020
7749e75
Addressed review comments for Even
wonder-sk Mar 30, 2020
2cfd699
Make sure that "protoc" tool is available
wonder-sk Mar 31, 2020
a475af2
Force protobuf package installation while it is not in qgis-dev-deps
wonder-sk Mar 31, 2020
c9f519a
Revert last commit: qgis-dev-deps now includes protobuf (thanks Jürgen!)
wonder-sk Apr 1, 2020
43415ee
Actually try to include protobuf-devel
wonder-sk Apr 1, 2020
7e71b23
Hopefully this fixes the win build
wonder-sk Apr 2, 2020
1c4042b
More windows build fixes
wonder-sk Apr 2, 2020
18bd8ab
Fix the fix on windows
wonder-sk Apr 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@ IF(WITH_CORE)
MESSAGE (SEND_ERROR "sqlite3 dependency was not found!")
ENDIF (NOT SQLITE3_FOUND)

FIND_PACKAGE(Protobuf REQUIRED) # for decoding of vector tiles in MVT format
MESSAGE(STATUS "Found Protobuf: ${Protobuf_LIBRARIES}")
FIND_PACKAGE(ZLIB REQUIRED) # for decompression of vector tiles in MBTiles file
MESSAGE(STATUS "Found zlib: ${ZLIB_LIBRARIES}")

# optional
IF (WITH_POSTGRESQL)
FIND_PACKAGE(Postgres) # PostgreSQL provider
Expand Down
1 change: 1 addition & 0 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/src/core/symbology
${CMAKE_SOURCE_DIR}/src/core/classification
${CMAKE_SOURCE_DIR}/src/core/validity
${CMAKE_SOURCE_DIR}/src/core/vectortile
wonder-sk marked this conversation as resolved.
Show resolved Hide resolved
${CMAKE_SOURCE_DIR}/src/plugins
${CMAKE_SOURCE_DIR}/external
${CMAKE_SOURCE_DIR}/external/nlohmann
Expand Down
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Original file line number Diff line number Diff line change
Expand Up @@ -534,3 +534,4 @@
%Include auto_generated/gps/qgsgpsconnectionregistry.sip
%Include auto_generated/symbology/qgsmasksymbollayer.sip
%Include auto_generated/qgsuserprofile.sip
%Include auto_generated/vectortile/qgsvectortilelayer.sip
2 changes: 1 addition & 1 deletion scripts/astyle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ astyleit() {

for f in "$@"; do
case "$f" in
src/plugins/grass/qtermwidget/*|external/o2/*|external/qt-unix-signals/*|external/rtree/*|external/astyle/*|external/kdbush/*|external/poly2tri/*|external/wintoast/*|external/qt3dextra-headers/*|external/meshOptimizer/*|python/ext-libs/*|ui_*.py|*.astyle|tests/testdata/*|editors/*)
src/plugins/grass/qtermwidget/*|external/o2/*|external/qt-unix-signals/*|external/rtree/*|external/astyle/*|external/kdbush/*|external/poly2tri/*|external/wintoast/*|external/qt3dextra-headers/*|external/meshOptimizer/*|python/ext-libs/*|ui_*.py|*.astyle|tests/testdata/*|editors/*|src/core/vectortile/*.pb.*)
echo -ne "$f skipped $elcr"
continue
;;
Expand Down
25 changes: 25 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ SET(QGIS_CORE_SRCS
qgsmapunitscale.cpp
qgsmargins.cpp
qgsmaskidprovider.cpp
qgsmbtilesreader.cpp
qgsmessagelog.cpp
qgsmessageoutput.cpp
qgsmimedatautils.cpp
Expand Down Expand Up @@ -395,6 +396,7 @@ SET(QGIS_CORE_SRCS
qgstessellator.cpp
qgstextrenderer.cpp
qgstilecache.cpp
qgstiles.cpp
qgstolerance.cpp
qgstracer.cpp
qgstranslationcontext.cpp
Expand Down Expand Up @@ -635,6 +637,14 @@ SET(QGIS_CORE_SRCS
validity/qgsvaliditycheckcontext.cpp
validity/qgsvaliditycheckregistry.cpp

vectortile/qgsvectortilebasicrenderer.cpp
vectortile/qgsvectortilelayer.cpp
vectortile/qgsvectortilelayerrenderer.cpp
vectortile/qgsvectortileloader.cpp
vectortile/qgsvectortilemvtdecoder.cpp
vectortile/qgsvectortileutils.cpp
vectortile/vector_tile.pb.cc

${CMAKE_CURRENT_BINARY_DIR}/qgsexpression_texts.cpp

qgsuserprofile.cpp
Expand Down Expand Up @@ -833,6 +843,7 @@ SET(QGIS_CORE_HDRS
qgsmapunitscale.h
qgsmargins.h
qgsmaskidprovider.h
qgsmbtilesreader.h
qgsmessagelog.h
qgsmessageoutput.h
qgsmimedatautils.h
Expand Down Expand Up @@ -924,6 +935,7 @@ SET(QGIS_CORE_HDRS
qgstextrenderer.h
qgsthreadingutils.h
qgstilecache.h
qgstiles.h
qgstolerance.h
qgstracer.h
qgstrackedvectorlayertools.h
Expand Down Expand Up @@ -1319,6 +1331,14 @@ SET(QGIS_CORE_HDRS
validity/qgsabstractvaliditycheck.h
validity/qgsvaliditycheckcontext.h
validity/qgsvaliditycheckregistry.h

vectortile/qgsvectortilebasicrenderer.h
vectortile/qgsvectortilelayer.h
vectortile/qgsvectortilelayerrenderer.h
vectortile/qgsvectortileloader.h
vectortile/qgsvectortilemvtdecoder.h
vectortile/qgsvectortilerenderer.h
vectortile/qgsvectortileutils.h
)

SET(QGIS_CORE_PRIVATE_HDRS
Expand Down Expand Up @@ -1408,6 +1428,7 @@ INCLUDE_DIRECTORIES(
symbology
mesh
validity
vectortile
${CMAKE_SOURCE_DIR}/external
${CMAKE_SOURCE_DIR}/external/nlohmann
${CMAKE_SOURCE_DIR}/external/kdbush/include
Expand All @@ -1429,6 +1450,8 @@ INCLUDE_DIRECTORIES(SYSTEM
${QCA_INCLUDE_DIR}
${QTKEYCHAIN_INCLUDE_DIR}
${Qt5SerialPort_INCLUDE_DIRS}
${Protobuf_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
)


Expand Down Expand Up @@ -1563,6 +1586,8 @@ TARGET_LINK_LIBRARIES(qgis_core
${SQLITE3_LIBRARY}
${SPATIALITE_LIBRARY}
${LIBZIP_LIBRARY}
${Protobuf_LIBRARIES}
${ZLIB_LIBRARIES}
)

IF (FORCE_STATIC_PROVIDERS)
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
#ifndef QGSMBTILESREADER_H
#define QGSMBTILESREADER_H

#include "qgis_core.h"

#include "sqlite3.h"
#include "qgssqliteutils.h"

class QImage;
class QgsRectangle;

class QgsMBTilesReader
class CORE_EXPORT QgsMBTilesReader
{
public:
explicit QgsMBTilesReader( const QString &filename );
Expand Down
259 changes: 259 additions & 0 deletions src/core/vectortile/qgsvectortilebasicrenderer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/***************************************************************************
qgsvectortilebasicrenderer.cpp
--------------------------------------
Date : March 2020
Copyright : (C) 2020 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 "qgsvectortilebasicrenderer.h"

#include "qgslinesymbollayer.h"
#include "qgssymbollayerutils.h"
#include "qgsvectortileutils.h"


QgsVectorTileBasicRendererStyle::QgsVectorTileBasicRendererStyle( const QString &stName, const QString &laName, QgsWkbTypes::GeometryType geomType )
: mStyleName( stName )
, mLayerName( laName )
, mGeometryType( geomType )
{
}

QgsVectorTileBasicRendererStyle::QgsVectorTileBasicRendererStyle( const QgsVectorTileBasicRendererStyle &other )
{
operator=( other );
}

QgsVectorTileBasicRendererStyle &QgsVectorTileBasicRendererStyle::operator=( const QgsVectorTileBasicRendererStyle &other )
{
mStyleName = other.mStyleName;
mLayerName = other.mLayerName;
mGeometryType = other.mGeometryType;
mSymbol.reset( other.mSymbol ? other.mSymbol->clone() : nullptr );
mEnabled = other.mEnabled;
mExpression = other.mExpression;
mMinZoomLevel = other.mMinZoomLevel;
mMaxZoomLevel = other.mMaxZoomLevel;
return *this;
}

void QgsVectorTileBasicRendererStyle::setSymbol( QgsSymbol *sym )
{
mSymbol.reset( sym );
}

void QgsVectorTileBasicRendererStyle::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
{
elem.setAttribute( "name", mStyleName );
elem.setAttribute( "layer", mLayerName );
elem.setAttribute( "geometry", mGeometryType );
elem.setAttribute( "enabled", mEnabled ? "1" : "0" );
elem.setAttribute( "expression", mExpression );
elem.setAttribute( "min-zoom", mMinZoomLevel );
elem.setAttribute( "max-zoom", mMaxZoomLevel );

QDomDocument doc = elem.ownerDocument();
QgsSymbolMap symbols;
symbols[QStringLiteral( "0" )] = mSymbol.get();
QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
elem.appendChild( symbolsElem );
}

void QgsVectorTileBasicRendererStyle::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
mStyleName = elem.attribute( "name" );
mLayerName = elem.attribute( "layer" );
mGeometryType = static_cast<QgsWkbTypes::GeometryType>( elem.attribute( "geometry" ).toInt() );
mEnabled = elem.attribute( "enabled" ).toInt();
mExpression = elem.attribute( "expression" );
mMinZoomLevel = elem.attribute( "min-zoom" ).toInt();
mMaxZoomLevel = elem.attribute( "max-zoom" ).toInt();

mSymbol.reset();
QDomElement symbolsElem = elem.firstChildElement( QStringLiteral( "symbols" ) );
if ( !symbolsElem.isNull() )
{
QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
if ( !symbolMap.contains( QStringLiteral( "0" ) ) )
{
mSymbol.reset( symbolMap.take( QStringLiteral( "0" ) ) );
}
}
}

////////


QgsVectorTileBasicRenderer::QgsVectorTileBasicRenderer()
{
setDefaultStyle();
}

QString QgsVectorTileBasicRenderer::type() const
{
return "basic";
}

QgsVectorTileBasicRenderer *QgsVectorTileBasicRenderer::clone() const
{
QgsVectorTileBasicRenderer *r = new QgsVectorTileBasicRenderer;
r->mStyles = mStyles;
r->mStyles.detach(); // make a deep copy to make sure symbols get cloned
return r;
}

void QgsVectorTileBasicRenderer::startRender( QgsRenderContext &context, int tileZoom, const QgsTileRange &tileRange )
{
Q_UNUSED( context )
Q_UNUSED( tileRange )
// figure out required fields for different layers
for ( const QgsVectorTileBasicRendererStyle &layerStyle : qgis::as_const( mStyles ) )
{
if ( layerStyle.isActive( tileZoom ) && !layerStyle.filterExpression().isEmpty() )
{
QgsExpression expr( layerStyle.filterExpression() );
mRequiredFields[layerStyle.layerName()].unite( expr.referencedColumns() );
}
}
}

QMap<QString, QSet<QString> > QgsVectorTileBasicRenderer::usedAttributes( const QgsRenderContext & )
{
return mRequiredFields;
}

void QgsVectorTileBasicRenderer::stopRender( QgsRenderContext &context )
{
Q_UNUSED( context )
}

void QgsVectorTileBasicRenderer::renderTile( const QgsVectorTileRendererData &tile, QgsRenderContext &context )
{
const QgsVectorTileFeatures tileData = tile.features;
int zoomLevel = tile.id.zoomLevel();

for ( const QgsVectorTileBasicRendererStyle &layerStyle : qgis::as_const( mStyles ) )
{
if ( !layerStyle.isActive( zoomLevel ) )
continue;

QgsFields fields = QgsVectorTileUtils::makeQgisFields( mRequiredFields[layerStyle.layerName()] );

QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) );
scope->setFields( fields );
context.expressionContext().appendScope( scope );

QgsExpression filterExpression( layerStyle.filterExpression() );
filterExpression.prepare( &context.expressionContext() );

QgsSymbol *sym = layerStyle.symbol();
sym->startRender( context, QgsFields() );
if ( layerStyle.layerName().isEmpty() )
{
// matching all layers
for ( QString layerName : tileData.keys() )
{
for ( const QgsFeature &f : tileData[layerName] )
{
scope->setFeature( f );
if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() )
continue;

if ( QgsWkbTypes::geometryType( f.geometry().wkbType() ) == layerStyle.geometryType() )
sym->renderFeature( f, context );
}
}
}
else if ( tileData.contains( layerStyle.layerName() ) )
{
// matching one particular layer
for ( const QgsFeature &f : tileData[layerStyle.layerName()] )
{
scope->setFeature( f );
if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() )
continue;

if ( QgsWkbTypes::geometryType( f.geometry().wkbType() ) == layerStyle.geometryType() )
sym->renderFeature( f, context );
}
}
sym->stopRender( context );

delete context.expressionContext().popScope();
wonder-sk marked this conversation as resolved.
Show resolved Hide resolved
}
}

void QgsVectorTileBasicRenderer::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
{
QDomDocument doc = elem.ownerDocument();
QDomElement elemStyles = doc.createElement( "styles" );
wonder-sk marked this conversation as resolved.
Show resolved Hide resolved
for ( const QgsVectorTileBasicRendererStyle &layerStyle : mStyles )
{
QDomElement elemStyle = doc.createElement( "style" );
layerStyle.writeXml( elemStyle, context );
elemStyles.appendChild( elemStyle );
}
elem.appendChild( elemStyles );
}

void QgsVectorTileBasicRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
mStyles.clear();

QDomElement elemStyles = elem.firstChildElement( "styles" );
QDomElement elemStyle = elemStyles.firstChildElement( "style" );
while ( !elemStyle.isNull() )
{
QgsVectorTileBasicRendererStyle layerStyle;
layerStyle.readXml( elemStyle, context );
mStyles.append( layerStyle );
}
}

void QgsVectorTileBasicRenderer::setStyles( const QList<QgsVectorTileBasicRendererStyle> &styles )
{
mStyles = styles;
}

QList<QgsVectorTileBasicRendererStyle> QgsVectorTileBasicRenderer::styles() const
{
return mStyles;
}

void QgsVectorTileBasicRenderer::setDefaultStyle()
{
QColor color = Qt::blue;
wonder-sk marked this conversation as resolved.
Show resolved Hide resolved
QColor polygonColor = color;
polygonColor.setAlpha( 100 );
QColor pointColor = Qt::red;

QgsFillSymbol *polygonSymbol = static_cast<QgsFillSymbol *>( QgsLineSymbol::defaultSymbol( QgsWkbTypes::PolygonGeometry ) );
polygonSymbol->setColor( polygonColor );

QgsLineSymbol *lineSymbol = static_cast<QgsLineSymbol *>( QgsLineSymbol::defaultSymbol( QgsWkbTypes::LineGeometry ) );
lineSymbol->setColor( color );

QgsMarkerSymbol *pointSymbol = static_cast<QgsMarkerSymbol *>( QgsLineSymbol::defaultSymbol( QgsWkbTypes::PointGeometry ) );
pointSymbol->setColor( pointColor );

QgsVectorTileBasicRendererStyle st1( "polygons", QString(), QgsWkbTypes::PolygonGeometry );
st1.setSymbol( polygonSymbol );

QgsVectorTileBasicRendererStyle st2( "lines", QString(), QgsWkbTypes::LineGeometry );
st2.setSymbol( lineSymbol );

QgsVectorTileBasicRendererStyle st3( "points", QString(), QgsWkbTypes::PointGeometry );
st3.setSymbol( pointSymbol );

QList<QgsVectorTileBasicRendererStyle> lst;
lst << st1 << st2 << st3;
setStyles( lst );
}
Loading