29 : QPaintEngine( QPaintEngine::AllFeatures )
30 , mUsePathStroker( usePathStroker )
36 mStrokedPathsSegments = segments;
41 mSimplifyTolerance = tolerance;
56 return QPaintEngine::User;
61 if ( mUsePathStroker && state.state().testFlag( QPaintEngine::DirtyFlag::DirtyPen ) )
70 QgsDebugError( QStringLiteral(
"QgsGeometryPaintEngine does not support drawImage method" ) );
76 QgsDebugError( QStringLiteral(
"QgsGeometryPaintEngine does not support drawPixmap method" ) );
82 QgsDebugError( QStringLiteral(
"QgsGeometryPaintEngine does not support drawTiledPixmap method" ) );
89 if ( transform.isIdentity() )
91 for (
int i = 0; i < lineCount; ++i, ++lines )
94 QVector<double> {
static_cast< double >( lines->x1() ),
static_cast< double >( lines->x2() ) },
95 QVector<double> {
static_cast< double >( lines->y1() ),
static_cast< double >( lines->y2() ) } )
101 for (
int i = 0; i < lineCount; ++i, ++lines )
103 double x1 = lines->x1();
104 double x2 = lines->x2();
105 double y1 = lines->y1();
106 double y2 = lines->y2();
108 double tx1, tx2, ty1, ty2;
109 transform.map( x1, y1, &tx1, &ty1 );
110 transform.map( x2, y2, &tx2, &ty2 );
113 QVector<double> { tx1, tx2 },
114 QVector<double> { ty1, ty2 } )
122 if ( mUsePathStroker )
125 QPaintEngine::drawLines( lines, lineCount );
129 const QTransform transform = painter()->combinedTransform();
136 if ( mUsePathStroker )
139 QPaintEngine::drawLines( lines, lineCount );
143 const QTransform transform = painter()->combinedTransform();
152 if ( transform.isIdentity() )
154 for (
int i = 0; i < pointCount; ++i, ++points )
157 static_cast< double >( points->y() ) ) );
162 for (
int i = 0; i < pointCount; ++i, ++points )
164 double x = points->x();
165 double y = points->y();
168 transform.map( x, y, &tx, &ty );
177 const QTransform transform = painter()->combinedTransform();
183 const QTransform transform = painter()->combinedTransform();
191 if ( transform.isIdentity() )
193 for (
int i = 0; i < rectCount; ++i, ++rects )
196 QVector<double> {
static_cast< double >( rects->left() ),
197 static_cast< double >( rects->right() ),
198 static_cast< double >( rects->right() ),
199 static_cast< double >( rects->left() ),
200 static_cast< double>( rects->left() )
202 QVector<double> {
static_cast< double >( rects->bottom() ),
203 static_cast< double >( rects->bottom() ),
204 static_cast< double >( rects->top() ),
205 static_cast< double >( rects->top() ),
206 static_cast< double >( rects->bottom() )
213 for (
int i = 0; i < rectCount; ++i, ++rects )
215 const double left = rects->left();
216 const double right = rects->right();
217 const double top = rects->top();
218 const double bottom = rects->bottom();
220 double bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, topLeftX, topLeftY, topRightX, topRightY;
221 transform.map( left, bottom, &bottomLeftX, &bottomLeftY );
222 transform.map( right, bottom, &bottomRightX, &bottomRightY );
223 transform.map( left, top, &topLeftX, &topLeftY );
224 transform.map( right, top, &topRightX, &topRightY );
227 QVector<double> { bottomLeftX, bottomRightX, topRightX, topLeftX, bottomLeftX },
228 QVector<double> { bottomLeftY, bottomRightY, topRightY, topLeftY, bottomLeftY } );
236 const QTransform transform = painter()->combinedTransform();
242 const QTransform transform = painter()->combinedTransform();
251 x.resize( pointCount );
252 y.resize( pointCount );
253 double *xData = x.data();
254 double *yData = y.data();
256 if ( transform.isIdentity() )
258 for (
int i = 0; i < pointCount; ++i, ++points )
260 *xData++ = points->x();
261 *yData++ = points->y();
266 for (
int i = 0; i < pointCount; ++i, ++points )
268 const double x = points->x();
269 const double y = points->y();
271 transform.map( x, y, &tx, &ty );
280 case QPaintEngine::PolylineMode:
281 if ( simplifyTolerance > 0 )
287 case QPaintEngine::OddEvenMode:
288 case QPaintEngine::WindingMode:
289 case QPaintEngine::ConvexMode:
290 if ( simplifyTolerance > 0 )
300 if ( mUsePathStroker && mode == PolygonDrawMode::PolylineMode )
303 if ( pointCount > 0 )
306 path.moveTo( *points++ );
307 for (
int i = 1; i < pointCount; ++i )
309 path.lineTo( *points++ );
316 const QTransform transform = painter()->combinedTransform();
317 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
323 if ( mUsePathStroker )
326 if ( pointCount > 0 )
329 path.moveTo( *points++ );
330 for (
int i = 1; i < pointCount; ++i )
332 path.lineTo( *points++ );
339 const QTransform transform = painter()->combinedTransform();
340 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
346 std::unique_ptr< QgsAbstractGeometry > buffered;
347 if ( mSimplifyTolerance > 0 )
354 const double preBufferedSimplificationFactor = mSimplifyTolerance * 0.75;
355 std::unique_ptr< QgsLineString > simplified( line->
simplifyByDistance( preBufferedSimplificationFactor ) );
357 buffered.reset(
geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
362 buffered.reset(
geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
369 buffered->transform( *matrix );
371 if (
QgsGeometryCollection *bufferedCollection = qgsgeometry_cast< QgsGeometryCollection * >( buffered.get() ) )
373 if ( mSimplifyTolerance > 0 )
375 for (
auto it = bufferedCollection->const_parts_begin(); it != bufferedCollection->const_parts_end(); ++it )
377 mGeometry.
addGeometry( ( *it )->simplifyByDistance( mSimplifyTolerance ) );
382 mGeometry.
addGeometries( bufferedCollection->takeGeometries() );
387 if ( mSimplifyTolerance > 0 )
389 mGeometry.
addGeometry( buffered->simplifyByDistance( mSimplifyTolerance ) );
398Qgis::EndCapStyle QgsGeometryPaintEngine::penStyleToCapStyle( Qt::PenCapStyle style )
408 case Qt::MPenCapStyle:
416Qgis::JoinStyle QgsGeometryPaintEngine::penStyleToJoinStyle( Qt::PenJoinStyle style )
421 case Qt::SvgMiterJoin:
427 case Qt::MPenJoinStyle:
435void QgsGeometryPaintEngine::addSubpathGeometries(
const QPainterPath &path,
const QTransform &matrix )
437 if ( path.isEmpty() )
440 const bool transformIsIdentity = matrix.isIdentity();
443 const Qgis::JoinStyle joinStyle = penStyleToJoinStyle( mPen.joinStyle() );
444 const double penWidth = mPen.widthF() <= 0 ? 1 : mPen.widthF();
445 const double miterLimit = mPen.miterLimit();
447 QVector< double > currentX;
448 QVector< double > currentY;
449 const int count = path.elementCount();
452 std::vector< std::unique_ptr< QgsPolygon > > queuedPolygons;
454 for (
int i = 0; i < count; ++i )
456 const QPainterPath::Element &e = path.elementAt( i );
459 case QPainterPath::MoveToElement:
461 if ( currentX.size() > 1 )
463 std::unique_ptr< QgsLineString > line = std::make_unique< QgsLineString >( currentX, currentY );
464 if ( mUsePathStroker )
466 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
468 else if ( line->isClosed() )
470 if ( !transformIsIdentity )
471 line->transform( matrix );
473 if ( mSimplifyTolerance > 0 )
475 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->simplifyByDistance( mSimplifyTolerance ) ) );
480 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
485 if ( !transformIsIdentity )
486 line->transform( matrix );
487 if ( mSimplifyTolerance > 0 )
489 mGeometry.
addGeometry( line->simplifyByDistance( mSimplifyTolerance ) );
498 currentX.resize( 0 );
499 currentY.resize( 0 );
501 currentX.reserve( 16 );
502 currentY.reserve( 16 );
508 case QPainterPath::LineToElement:
515 case QPainterPath::CurveToElement:
517 Q_ASSERT( path.elementAt( i + 1 ).type == QPainterPath::CurveToDataElement );
518 Q_ASSERT( path.elementAt( i + 2 ).type == QPainterPath::CurveToDataElement );
520 const double x1 = path.elementAt( i - 1 ).x;
521 const double y1 = path.elementAt( i - 1 ).y;
523 const double x3 = path.elementAt( i + 1 ).x;
524 const double y3 = path.elementAt( i + 1 ).y;
526 const double x4 = path.elementAt( i + 2 ).x;
527 const double y4 = path.elementAt( i + 2 ).y;
536 currentX << bezier->xVector();
537 currentY << bezier->yVector();
542 case QPainterPath::CurveToDataElement:
543 Q_ASSERT( !
"addSubpathGeometries(), bad element type" );
548 if ( currentX.size() > 1 )
550 std::unique_ptr< QgsLineString > line = std::make_unique< QgsLineString >( currentX, currentY );
551 if ( mUsePathStroker )
553 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
555 else if ( line->isClosed() )
557 if ( !transformIsIdentity )
558 line->transform( matrix );
559 if ( mSimplifyTolerance > 0 )
561 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->simplifyByDistance( mSimplifyTolerance ) ) );
566 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
571 if ( !transformIsIdentity )
572 line->transform( matrix );
573 if ( mSimplifyTolerance > 0 )
575 mGeometry.
addGeometry( line->simplifyByDistance( mSimplifyTolerance ) );
585 if ( queuedPolygons.empty() )
591 tempMultiPolygon.
reserve(
static_cast< int >( queuedPolygons.size() ) );
592 for (
auto &part : queuedPolygons )
598 QgsGeos geosCollection( &tempMultiPolygon );
603 for (
auto it = g->const_parts_begin(); it != g->const_parts_end(); ++it )
611 const QTransform transform = painter()->combinedTransform();
612 addSubpathGeometries( path, transform );
622 mPaintEngine = std::make_unique<QgsGeometryPaintEngine>( usePathStroker );
628 mPaintEngine->setStrokedPathSegments( segments );
634 mPaintEngine->setSimplificationTolerance( tolerance );
639 return mPaintEngine.get();
650 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().width() );
653 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().height() );
662 case PdmPhysicalDpiX:
666 case PdmPhysicalDpiY:
675 case PdmDevicePixelRatio:
678 case PdmDevicePixelRatioScaled:
679 val =
static_cast< int >( 1 * QPaintDevice::devicePixelRatioFScale() );
683 qWarning(
"QPicture::metric: Invalid metric command" );
690 return mPaintEngine->geometry();
696 QPainter painter( &device );
697 painter.drawPath( path );
JoinStyle
Join styles for buffers.
@ Bevel
Use beveled joins.
@ Round
Use rounded joins.
@ Miter
Use mitered joins.
EndCapStyle
End cap styles for buffers.
@ Flat
Flat cap (in line with start/end of line)
@ Square
Square cap (extends past start/end of line by buffer distance)
@ Linework
Combines all rings into a set of noded lines and then extracts valid polygons from that linework.
Abstract base class for all geometries.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
void reserve(int size)
Attempts to allocate memory for at least size geometries.
virtual bool addGeometries(const QVector< QgsAbstractGeometry * > &geometries)
Adds a list of geometries to the collection, transferring ownership to the collection.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
int numGeometries() const
Returns the number of geometries within the collection.
A paint device which converts everything renderer to a QgsGeometry representation of the rendered sha...
QgsGeometryPaintDevice(bool usePathStroker=false)
Constructor for QgsGeometryPaintDevice.
void setStrokedPathSegments(int segments)
Sets the number of segments to use when drawing stroked paths with a rounded pen.
int metric(PaintDeviceMetric metric) const override
void setSimplificationTolerance(double tolerance)
Sets a simplification tolerance (in painter units) to use for on-the-fly simplification of geometries...
QPaintEngine * paintEngine() const override
static QgsGeometry painterPathToGeometry(const QPainterPath &path)
Converts a painter path to a QgsGeometry.
const QgsAbstractGeometry & geometry() const
Returns the rendered geometry.
void setSimplificationTolerance(double tolerance)
Sets a simplification tolerance (in painter units) to use for on-the-fly simplification of geometries...
void drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags=Qt::AutoColor) final
void drawRects(const QRectF *rects, int rectCount) final
void drawPolygon(const QPointF *points, int pointCount, QPaintEngine::PolygonDrawMode mode) final
void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) final
void drawPoints(const QPointF *points, int pointCount) final
bool begin(QPaintDevice *) final
QgsGeometryPaintEngine(bool usePathStroker=false)
Constructor for QgsGeometryPaintEngine.
void drawLines(const QLineF *lines, int lineCount) final
QPaintEngine::Type type() const final
void drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &p) final
void updateState(const QPaintEngineState &) final
void drawPath(const QPainterPath &path) final
void setStrokedPathSegments(int segments)
Sets the number of segments to use when drawing stroked paths with a rounded pen.
A geometry is the spatial representation of a feature.
Does vector analysis using the geos library and handles import, export, exception handling*.
Line string geometry type, with support for z-dimension and m-values.
QgsLineString * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
static QgsLineString * fromBezierCurve(const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments=30)
Returns a new linestring created by segmentizing the bezier curve between start and end,...
Multi polygon geometry collection.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
static int qtDefaultDpiY()
Returns the default Qt vertical DPI.
static int qtDefaultDpiX()
Returns the default Qt horizontal DPI.
Point geometry type, with support for z-dimension and m-values.
Contains geos related utilities and functions.
void drawPointsImp(const QTransform &transform, QgsGeometryCollection &geometry, const T *points, int pointCount)
void drawRectsImp(const QTransform &transform, QgsGeometryCollection &geometry, const T *rects, int rectCount)
void drawLinesImp(const QTransform &transform, QgsGeometryCollection &geometry, const T *lines, int lineCount)
void drawPolygonImp(const QTransform &transform, QgsGeometryCollection &geometry, const T *points, int pointCount, QPaintEngine::PolygonDrawMode mode, double simplifyTolerance)
#define QgsDebugError(str)