mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-06 00:03:16 -05:00
In cases where we cannot convert the map extent back to a layer's
extent and have had to resort to fetching all features from a layer, defer the geometry clipping the map extent so that it occurs AFTER transforming the layer's geometries to the target map extent. This allows us to correctly clip the feature geometries in the case that the visible extent available from the render context for the layer is not accurate (i.e. it's a whole of globe fallback), and avoids rendering features which fall far outside of the visible map region. Fixes #38878
This commit is contained in:
parent
3ec1154796
commit
f3f226aa69
@ -47,6 +47,7 @@ to be rendered etc.
|
||||
LosslessImageRendering,
|
||||
ApplyScalingWorkaroundForTextRendering,
|
||||
Render3DMap,
|
||||
ApplyClipAfterReprojection,
|
||||
};
|
||||
typedef QFlags<QgsRenderContext::Flag> Flags;
|
||||
|
||||
|
||||
@ -344,9 +344,10 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter *painter, QgsLabelingEn
|
||||
QgsCoordinateTransform ct;
|
||||
|
||||
ct = mSettings.layerTransform( ml );
|
||||
bool haveExtentInLayerCrs = true;
|
||||
if ( ct.isValid() )
|
||||
{
|
||||
reprojectToLayerExtent( ml, ct, r1, r2 );
|
||||
haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
|
||||
}
|
||||
QgsDebugMsgLevel( "extent: " + r1.toString(), 3 );
|
||||
if ( !r1.isFinite() || !r2.isFinite() )
|
||||
@ -382,6 +383,8 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter *painter, QgsLabelingEn
|
||||
job.context.setLabelingEngine( labelingEngine2 );
|
||||
job.context.setCoordinateTransform( ct );
|
||||
job.context.setExtent( r1 );
|
||||
if ( !haveExtentInLayerCrs )
|
||||
job.context.setFlag( QgsRenderContext::ApplyClipAfterReprojection, true );
|
||||
|
||||
if ( mFeatureFilterProvider )
|
||||
job.context.setFeatureFilterProvider( mFeatureFilterProvider );
|
||||
|
||||
@ -84,6 +84,7 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject
|
||||
LosslessImageRendering = 0x1000, //!< Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some destination devices (e.g. PDF). This flag only works with builds based on Qt 5.13 or later.
|
||||
ApplyScalingWorkaroundForTextRendering = 0x2000, //!< Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters scaled out by a large amount) when rendering text. Generally this is recommended, but it may incur some performance cost.
|
||||
Render3DMap = 0x4000, //!< Render is for a 3D map
|
||||
ApplyClipAfterReprojection = 0x8000, //!< Feature geometry clipping to mapExtent() must be performed after the geometries are transformed using coordinateTransform(). Usually feature geometry clipping occurs using the extent() in the layer's CRS prior to geometry transformation, but in some cases when extent() could not be accurately calculated it is necessary to clip geometries to mapExtent() AFTER transforming them using coordinateTransform().
|
||||
};
|
||||
Q_DECLARE_FLAGS( Flags, Flag )
|
||||
|
||||
|
||||
@ -110,9 +110,9 @@ QPolygonF QgsSymbol::_getLineString( QgsRenderContext &context, const QgsCurve &
|
||||
QPolygonF pts;
|
||||
|
||||
//apply clipping for large lines to achieve a better rendering performance
|
||||
if ( clipToExtent && nPoints > 1 )
|
||||
if ( clipToExtent && nPoints > 1 && !( context.flags() & QgsRenderContext::ApplyClipAfterReprojection ) )
|
||||
{
|
||||
const QgsRectangle &e = context.extent();
|
||||
const QgsRectangle e = context.extent();
|
||||
const double cw = e.width() / 10;
|
||||
const double ch = e.height() / 10;
|
||||
const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
|
||||
@ -143,6 +143,16 @@ QPolygonF QgsSymbol::_getLineString( QgsRenderContext &context, const QgsCurve &
|
||||
return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
|
||||
} ), pts.end() );
|
||||
|
||||
if ( clipToExtent && nPoints > 1 && context.flags() & QgsRenderContext::ApplyClipAfterReprojection )
|
||||
{
|
||||
// early clipping was not possible, so we have to apply it here after transformation
|
||||
const QgsRectangle e = context.mapExtent();
|
||||
const double cw = e.width() / 10;
|
||||
const double ch = e.height() / 10;
|
||||
const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
|
||||
pts = QgsClipper::clippedLine( pts, clipRect );
|
||||
}
|
||||
|
||||
QPointF *ptr = pts.data();
|
||||
for ( int i = 0; i < pts.size(); ++i, ++ptr )
|
||||
{
|
||||
@ -156,10 +166,6 @@ QPolygonF QgsSymbol::_getPolygonRing( QgsRenderContext &context, const QgsCurve
|
||||
{
|
||||
const QgsCoordinateTransform ct = context.coordinateTransform();
|
||||
const QgsMapToPixel &mtp = context.mapToPixel();
|
||||
const QgsRectangle &e = context.extent();
|
||||
const double cw = e.width() / 10;
|
||||
const double ch = e.height() / 10;
|
||||
QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
|
||||
|
||||
QPolygonF poly = curve.asQPolygonF();
|
||||
|
||||
@ -176,9 +182,12 @@ QPolygonF QgsSymbol::_getPolygonRing( QgsRenderContext &context, const QgsCurve
|
||||
}
|
||||
|
||||
//clip close to view extent, if needed
|
||||
const QRectF ptsRect = poly.boundingRect();
|
||||
if ( clipToExtent && !context.extent().contains( ptsRect ) )
|
||||
if ( clipToExtent && !( context.flags() & QgsRenderContext::ApplyClipAfterReprojection ) && !context.extent().contains( poly.boundingRect() ) )
|
||||
{
|
||||
const QgsRectangle e = context.extent();
|
||||
const double cw = e.width() / 10;
|
||||
const double ch = e.height() / 10;
|
||||
const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
|
||||
QgsClipper::trimPolygon( poly, clipRect );
|
||||
}
|
||||
|
||||
@ -202,6 +211,16 @@ QPolygonF QgsSymbol::_getPolygonRing( QgsRenderContext &context, const QgsCurve
|
||||
return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
|
||||
} ), poly.end() );
|
||||
|
||||
if ( clipToExtent && context.flags() & QgsRenderContext::ApplyClipAfterReprojection && !context.mapExtent().contains( poly.boundingRect() ) )
|
||||
{
|
||||
// early clipping was not possible, so we have to apply it here after transformation
|
||||
const QgsRectangle e = context.mapExtent();
|
||||
const double cw = e.width() / 10;
|
||||
const double ch = e.height() / 10;
|
||||
const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
|
||||
QgsClipper::trimPolygon( poly, clipRect );
|
||||
}
|
||||
|
||||
QPointF *ptr = poly.data();
|
||||
for ( int i = 0; i < poly.size(); ++i, ++ptr )
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user