Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add "Fill Above" mode for elevation profile drawing
Fixes #51074
  • Loading branch information
nyalldawson committed May 22, 2023
1 parent 7b42acd commit 6c4f96a
Show file tree
Hide file tree
Showing 12 changed files with 71 additions and 1 deletion.
1 change: 1 addition & 0 deletions images/images.qrc
Expand Up @@ -985,6 +985,7 @@
<file>composer/refreshing_item.svg</file>
<file>themes/default/mActionTextAlongLine.svg</file>
<file>themes/default/mActionNewElevationProfile.svg</file>
<file>themes/default/mIconSurfaceElevationFillAbove.svg</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>
Expand Down
1 change: 1 addition & 0 deletions images/themes/default/mIconSurfaceElevationFillAbove.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion python/core/auto_additions/qgis.py
Expand Up @@ -2477,7 +2477,8 @@
# monkey patching scoped based enum
Qgis.ProfileSurfaceSymbology.Line.__doc__ = "The elevation surface will be rendered using a line symbol"
Qgis.ProfileSurfaceSymbology.FillBelow.__doc__ = "The elevation surface will be rendered using a fill symbol below the surface level"
Qgis.ProfileSurfaceSymbology.__doc__ = 'Surface symbology type for elevation profile plots.\n\n.. versionadded:: 3.26\n\n' + '* ``Line``: ' + Qgis.ProfileSurfaceSymbology.Line.__doc__ + '\n' + '* ``FillBelow``: ' + Qgis.ProfileSurfaceSymbology.FillBelow.__doc__
Qgis.ProfileSurfaceSymbology.FillAbove.__doc__ = "The elevation surface will be rendered using a fill symbol above the surface level (since QGIS 3.32)"
Qgis.ProfileSurfaceSymbology.__doc__ = 'Surface symbology type for elevation profile plots.\n\n.. versionadded:: 3.26\n\n' + '* ``Line``: ' + Qgis.ProfileSurfaceSymbology.Line.__doc__ + '\n' + '* ``FillBelow``: ' + Qgis.ProfileSurfaceSymbology.FillBelow.__doc__ + '\n' + '* ``FillAbove``: ' + Qgis.ProfileSurfaceSymbology.FillAbove.__doc__
# --
Qgis.ProfileSurfaceSymbology.baseClass = Qgis
# monkey patching scoped based enum
Expand Down
1 change: 1 addition & 0 deletions python/core/auto_generated/qgis.sip.in
Expand Up @@ -1513,6 +1513,7 @@ The development version
{
Line,
FillBelow,
FillAbove,
};

enum class VectorProfileType
Expand Down
3 changes: 3 additions & 0 deletions src/app/mesh/qgsmeshelevationpropertieswidget.cpp
Expand Up @@ -33,6 +33,7 @@ QgsMeshElevationPropertiesWidget::QgsMeshElevationPropertiesWidget( QgsMeshLayer
mFillStyleButton->setSymbolType( Qgis::SymbolType::Fill );
mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationLine.svg" ) ), tr( "Line" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::Line ) );
mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationFillBelow.svg" ) ), tr( "Fill Below" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::FillBelow ) );
mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationFillAbove.svg" ) ), tr( "Fill Above" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::FillAbove ) );

syncToLayer( layer );

Expand All @@ -48,6 +49,7 @@ QgsMeshElevationPropertiesWidget::QgsMeshElevationPropertiesWidget( QgsMeshLayer
mSymbologyStackedWidget->setCurrentWidget( mPageLine );
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
mSymbologyStackedWidget->setCurrentWidget( mPageFill );
break;
}
Expand Down Expand Up @@ -78,6 +80,7 @@ void QgsMeshElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer )
mSymbologyStackedWidget->setCurrentWidget( mPageLine );
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
mSymbologyStackedWidget->setCurrentWidget( mPageFill );
break;
}
Expand Down
3 changes: 3 additions & 0 deletions src/app/raster/qgsrasterelevationpropertieswidget.cpp
Expand Up @@ -34,6 +34,7 @@ QgsRasterElevationPropertiesWidget::QgsRasterElevationPropertiesWidget( QgsRaste
mFillStyleButton->setSymbolType( Qgis::SymbolType::Fill );
mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationLine.svg" ) ), tr( "Line" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::Line ) );
mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationFillBelow.svg" ) ), tr( "Fill Below" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::FillBelow ) );
mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationFillAbove.svg" ) ), tr( "Fill Above" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::FillAbove ) );

syncToLayer( layer );

Expand All @@ -51,6 +52,7 @@ QgsRasterElevationPropertiesWidget::QgsRasterElevationPropertiesWidget( QgsRaste
mSymbologyStackedWidget->setCurrentWidget( mPageLine );
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
mSymbologyStackedWidget->setCurrentWidget( mPageFill );
break;
}
Expand Down Expand Up @@ -83,6 +85,7 @@ void QgsRasterElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer )
mSymbologyStackedWidget->setCurrentWidget( mPageLine );
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
mSymbologyStackedWidget->setCurrentWidget( mPageFill );
break;
}
Expand Down
3 changes: 3 additions & 0 deletions src/app/vector/qgsvectorelevationpropertieswidget.cpp
Expand Up @@ -52,6 +52,7 @@ QgsVectorElevationPropertiesWidget::QgsVectorElevationPropertiesWidget( QgsVecto

mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationLine.svg" ) ), tr( "Line" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::Line ) );
mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationFillBelow.svg" ) ), tr( "Fill Below" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::FillBelow ) );
mStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconSurfaceElevationFillAbove.svg" ) ), tr( "Fill Above" ), static_cast< int >( Qgis::ProfileSurfaceSymbology::FillAbove ) );

initializeDataDefinedButton( mOffsetDDBtn, QgsMapLayerElevationProperties::ZOffset );
initializeDataDefinedButton( mExtrusionDDBtn, QgsMapLayerElevationProperties::ExtrusionHeight );
Expand Down Expand Up @@ -88,6 +89,7 @@ QgsVectorElevationPropertiesWidget::QgsVectorElevationPropertiesWidget( QgsVecto
mSymbologyStackedWidget->setCurrentWidget( mPageLine );
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
mSymbologyStackedWidget->setCurrentWidget( mPageFill );
break;
}
Expand Down Expand Up @@ -150,6 +152,7 @@ void QgsVectorElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer )
mSymbologyStackedWidget->setCurrentWidget( mPageLine );
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
mSymbologyStackedWidget->setCurrentWidget( mPageFill );
break;
}
Expand Down
14 changes: 14 additions & 0 deletions src/core/elevation/qgsabstractprofilesurfacegenerator.cpp
Expand Up @@ -148,6 +148,7 @@ void QgsAbstractProfileSurfaceResults::renderResults( QgsProfileRenderContext &c
mLineSymbol->startRender( context.renderContext() );
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
mFillSymbol->startRender( context.renderContext() );
break;
}
Expand Down Expand Up @@ -176,6 +177,12 @@ void QgsAbstractProfileSurfaceResults::renderResults( QgsProfileRenderContext &c
currentLine.append( currentLine.at( 0 ) );
mFillSymbol->renderPolygon( currentLine, nullptr, nullptr, context.renderContext() );
break;
case Qgis::ProfileSurfaceSymbology::FillAbove:
currentLine.append( context.worldTransform().map( QPointF( prevDistance, maxZ ) ) );
currentLine.append( context.worldTransform().map( QPointF( currentPartStartDistance, maxZ ) ) );
currentLine.append( currentLine.at( 0 ) );
mFillSymbol->renderPolygon( currentLine, nullptr, nullptr, context.renderContext() );
break;
}
}
prevDistance = pointIt.key();
Expand All @@ -199,6 +206,12 @@ void QgsAbstractProfileSurfaceResults::renderResults( QgsProfileRenderContext &c
currentLine.append( currentLine.at( 0 ) );
mFillSymbol->renderPolygon( currentLine, nullptr, nullptr, context.renderContext() );
break;
case Qgis::ProfileSurfaceSymbology::FillAbove:
currentLine.append( context.worldTransform().map( QPointF( prevDistance, maxZ ) ) );
currentLine.append( context.worldTransform().map( QPointF( currentPartStartDistance, maxZ ) ) );
currentLine.append( currentLine.at( 0 ) );
mFillSymbol->renderPolygon( currentLine, nullptr, nullptr, context.renderContext() );
break;
}
}

Expand All @@ -208,6 +221,7 @@ void QgsAbstractProfileSurfaceResults::renderResults( QgsProfileRenderContext &c
mLineSymbol->stopRender( context.renderContext() );
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
mFillSymbol->stopRender( context.renderContext() );
break;
}
Expand Down
1 change: 1 addition & 0 deletions src/core/qgis.h
Expand Up @@ -2579,6 +2579,7 @@ class CORE_EXPORT Qgis
{
Line, //!< The elevation surface will be rendered using a line symbol
FillBelow, //!< The elevation surface will be rendered using a fill symbol below the surface level
FillAbove, //!< The elevation surface will be rendered using a fill symbol above the surface level (since QGIS 3.32)
};
Q_ENUM( ProfileSurfaceSymbology );

Expand Down
3 changes: 3 additions & 0 deletions src/gui/elevation/qgselevationprofilelayertreeview.cpp
Expand Up @@ -130,6 +130,7 @@ QVariant QgsElevationProfileLayerTreeModel::data( const QModelIndex &index, int
}
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
if ( QgsFillSymbol *fillSymbol = elevationProperties->profileFillSymbol() )
{
symbol.reset( fillSymbol->clone() );
Expand All @@ -154,6 +155,7 @@ QVariant QgsElevationProfileLayerTreeModel::data( const QModelIndex &index, int
}
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
if ( QgsFillSymbol *fillSymbol = rlProps->profileFillSymbol() )
{
symbol.reset( fillSymbol->clone() );
Expand All @@ -175,6 +177,7 @@ QVariant QgsElevationProfileLayerTreeModel::data( const QModelIndex &index, int
}
break;
case Qgis::ProfileSurfaceSymbology::FillBelow:
case Qgis::ProfileSurfaceSymbology::FillAbove:
if ( QgsFillSymbol *fillSymbol = mlProps->profileFillSymbol() )
{
symbol.reset( fillSymbol->clone() );
Expand Down
39 changes: 39 additions & 0 deletions tests/src/python/test_qgsvectorlayerprofilegenerator.py
Expand Up @@ -1498,6 +1498,45 @@ def testRenderProfileAsSurfaceFillBelow(self):
res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14)
self.assertTrue(self.imageCheck('vector_lines_as_fill_below_surface', 'vector_lines_as_fill_below_surface', res))

def testRenderProfileAsSurfaceFillAbove(self):
vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory')
vl.setCrs(QgsCoordinateReferenceSystem())
self.assertTrue(vl.isValid())

for line in [
'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)',
'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)',
'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)',
'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)',
'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']:
f = QgsFeature()
f.setGeometry(QgsGeometry.fromWkt(line))
self.assertTrue(vl.dataProvider().addFeature(f))

vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute)
vl.elevationProperties().setType(Qgis.VectorProfileType.ContinuousSurface)
vl.elevationProperties().setProfileSymbology(Qgis.ProfileSurfaceSymbology.FillAbove)
fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'})
vl.elevationProperties().setRespectLayerSymbology(False)
vl.elevationProperties().setProfileFillSymbol(fill_symbol)
line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'})
vl.elevationProperties().setProfileLineSymbol(line_symbol)

curve = QgsLineString()
curve.fromWkt(
'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)')
req = QgsProfileRequest(curve)
req.setTransformContext(self.create_transform_context())

req.setCrs(QgsCoordinateReferenceSystem())

plot_renderer = QgsProfilePlotRenderer([vl], req)
plot_renderer.startGeneration()
plot_renderer.waitForFinished()

res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14)
self.assertTrue(self.imageCheck('vector_lines_as_fill_above_surface', 'vector_lines_as_fill_above_surface', res))

def testRenderLayerSymbology(self):
vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory')
vl.setCrs(QgsCoordinateReferenceSystem())
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 6c4f96a

Please sign in to comment.