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

Fix rendering of linestrings with nan z values #50549

Merged
merged 1 commit into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 19 additions & 5 deletions src/core/symbology/qgssymbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@
#include "qgssymbol.h"
#include "qgssymbollayer.h"

#include "qgslinesymbollayer.h"
#include "qgsmarkersymbollayer.h"
#include "qgsfillsymbollayer.h"
#include "qgsgeometrygeneratorsymbollayer.h"
#include "qgsmaptopixelgeometrysimplifier.h"
#include "qgslogger.h"
Expand All @@ -37,7 +34,6 @@
#include "qgsprojectstylesettings.h"
#include "qgsstyle.h"
#include "qgspainteffect.h"
#include "qgseffectstack.h"
#include "qgsvectorlayer.h"
#include "qgsfeature.h"
#include "qgsgeometry.h"
Expand Down Expand Up @@ -142,10 +138,13 @@ QPolygonF QgsSymbol::_getLineString3d( QgsRenderContext &context, const QgsCurve
}

// transform the points to screen coordinates
const QVector< double > preTransformPointsZ = pointsZ;
bool wasTransformed = false;
if ( ct.isValid() )
{
//create x, y arrays
const int nVertices = pointsX.size();
wasTransformed = true;

try
{
Expand All @@ -164,13 +163,25 @@ QPolygonF QgsSymbol::_getLineString3d( QgsRenderContext &context, const QgsCurve
const double *xIn = pointsX.data();
const double *yIn = pointsY.data();
const double *zIn = pointsZ.data();

const double *preTransformZIn = wasTransformed ? preTransformPointsZ.constData() : nullptr;

double *xOut = pointsX.data();
double *yOut = pointsY.data();
double *zOut = pointsZ.data();
int outSize = 0;
for ( int i = 0; i < size; ++i )
{
if ( std::isfinite( *xIn ) && std::isfinite( *yIn ) && std::isfinite( *zIn ) )
bool pointOk = std::isfinite( *xIn ) && std::isfinite( *yIn );

// skip z points which have been made non-finite during transformations only. Ie if:
// - we did no transformation, then always render even if non-finite z
// - we did transformation and z is finite then render
// - we did transformation and z is non-finite BUT input z was also non finite then render
// - we did transformation and z is non-finite AND input z WAS finite then skip
pointOk &= !wasTransformed || std::isfinite( *zIn ) || !std::isfinite( *preTransformZIn );

if ( pointOk )
{
*xOut++ = *xIn++;
*yOut++ = *yIn++;
Expand All @@ -183,6 +194,9 @@ QPolygonF QgsSymbol::_getLineString3d( QgsRenderContext &context, const QgsCurve
yIn++;
zIn++;
}

if ( preTransformZIn )
preTransformZIn++;
}
pointsX.resize( outSize );
pointsY.resize( outSize );
Expand Down
40 changes: 39 additions & 1 deletion tests/src/python/test_qgssymbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
Qgis,
QgsSymbolLayer,
QgsProperty,
QgsRasterFillSymbolLayer
QgsRasterFillSymbolLayer,
QgsPoint
)

from qgis.testing import unittest, start_app
Expand Down Expand Up @@ -719,6 +720,43 @@ def renderCollection(self, geom, symbol):

return image

def test_render_line_nan_z(self):
geom = QgsGeometry.fromPolyline([
QgsPoint(10, 10, 0),
QgsPoint(20, 20, 0),
QgsPoint(30, 10, float("nan")),
])

f = QgsFeature()
f.setGeometry(geom)

image = QImage(200, 200, QImage.Format_RGB32)

painter = QPainter()
ms = QgsMapSettings()
extent = geom.get().boundingBox()
# buffer extent by 10%
extent = extent.buffered((extent.height() + extent.width()) / 20.0)

ms.setExtent(extent)
ms.setOutputSize(image.size())
context = QgsRenderContext.fromMapSettings(ms)
context.setPainter(painter)
context.setScaleFactor(96 / 25.4) # 96 DPI

symbol = QgsLineSymbol.createSimple({'color': '#ffffff', 'line_width': '3'})

painter.begin(image)
try:
image.fill(QColor(0, 0, 0))
symbol.startRender(context)
symbol.renderFeature(f, context)
symbol.stopRender(context)
finally:
painter.end()

assert self.imageCheck('Linestring with nan z', 'linestring_nan_z', image)

def testGeometryCollectionRender(self):
tests = [{'name': 'Marker',
'wkt': 'GeometryCollection (Point(1 2))',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.