QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
qgsgeometrypaintdevice.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgeometrypaintdevice.cpp
3 --------------------------------------
4 Date : May 2024
5 Copyright : (C) 2024 by Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "qgspolygon.h"
18#include "qgslinestring.h"
19#include "qgsgeos.h"
20#include "qgsmultipolygon.h"
21#include "qgsmultilinestring.h"
22#include "qgspainting.h"
23
24//
25// QgsGeometryPaintEngine
26//
27
29 : QPaintEngine( QPaintEngine::AllFeatures ) // we lie and say we support all paint features, as we don't want Qt trying to be helpful and rasterizing shapes
30 , mUsePathStroker( usePathStroker )
31{
32}
33
35{
36 mStrokedPathsSegments = segments;
37}
38
40{
41 mSimplifyTolerance = tolerance;
42}
43
44bool QgsGeometryPaintEngine::begin( QPaintDevice * )
45{
46 return true;
47}
48
50{
51 return true;
52}
53
54QPaintEngine::Type QgsGeometryPaintEngine::type() const
55{
56 return QPaintEngine::User;
57}
58
59void QgsGeometryPaintEngine::updateState( const QPaintEngineState &state )
60{
61 if ( mUsePathStroker && state.state().testFlag( QPaintEngine::DirtyFlag::DirtyPen ) )
62 {
63 mPen = state.pen();
64 }
65}
66
67void QgsGeometryPaintEngine::drawImage( const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags )
68{
69 // ignore, we don't need to support raster drawing
70 QgsDebugError( QStringLiteral( "QgsGeometryPaintEngine does not support drawImage method" ) );
71}
72
73void QgsGeometryPaintEngine::drawPixmap( const QRectF &, const QPixmap &, const QRectF & )
74{
75 // ignore, we don't need to support raster drawing
76 QgsDebugError( QStringLiteral( "QgsGeometryPaintEngine does not support drawPixmap method" ) );
77}
78
79void QgsGeometryPaintEngine::drawTiledPixmap( const QRectF &, const QPixmap &, const QPointF & )
80{
81 // ignore, we don't need to support raster drawing
82 QgsDebugError( QStringLiteral( "QgsGeometryPaintEngine does not support drawTiledPixmap method" ) );
83}
84
85template <typename T>
86void drawLinesImp( const QTransform &transform, QgsGeometryCollection &geometry, const T *lines, int lineCount )
87{
88 geometry.reserve( geometry.numGeometries() + lineCount );
89 if ( transform.isIdentity() )
90 {
91 for ( int i = 0; i < lineCount; ++i, ++lines )
92 {
93 geometry.addGeometry( new QgsLineString(
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() ) } )
96 );
97 }
98 }
99 else
100 {
101 for ( int i = 0; i < lineCount; ++i, ++lines )
102 {
103 double x1 = lines->x1();
104 double x2 = lines->x2();
105 double y1 = lines->y1();
106 double y2 = lines->y2();
107
108 double tx1, tx2, ty1, ty2;
109 transform.map( x1, y1, &tx1, &ty1 );
110 transform.map( x2, y2, &tx2, &ty2 );
111
112 geometry.addGeometry( new QgsLineString(
113 QVector<double> { tx1, tx2 },
114 QVector<double> { ty1, ty2 } )
115 );
116 }
117 }
118}
119
120void QgsGeometryPaintEngine::drawLines( const QLineF *lines, int lineCount )
121{
122 if ( mUsePathStroker )
123 {
124 // if stroking we have no choice but to go via the QPainterPath route
125 QPaintEngine::drawLines( lines, lineCount );
126 }
127 else
128 {
129 const QTransform transform = painter()->combinedTransform();
130 drawLinesImp( transform, mGeometry, lines, lineCount );
131 }
132}
133
134void QgsGeometryPaintEngine::drawLines( const QLine *lines, int lineCount )
135{
136 if ( mUsePathStroker )
137 {
138 // if stroking we have no choice but to go via the QPainterPath route
139 QPaintEngine::drawLines( lines, lineCount );
140 }
141 else
142 {
143 const QTransform transform = painter()->combinedTransform();
144 drawLinesImp( transform, mGeometry, lines, lineCount );
145 }
146}
147
148template <typename T>
149void drawPointsImp( const QTransform &transform, QgsGeometryCollection &geometry, const T *points, int pointCount )
150{
151 geometry.reserve( geometry.numGeometries() + pointCount );
152 if ( transform.isIdentity() )
153 {
154 for ( int i = 0; i < pointCount; ++i, ++points )
155 {
156 geometry.addGeometry( new QgsPoint( static_cast< double >( points->x() ),
157 static_cast< double >( points->y() ) ) );
158 }
159 }
160 else
161 {
162 for ( int i = 0; i < pointCount; ++i, ++points )
163 {
164 double x = points->x();
165 double y = points->y();
166
167 double tx, ty;
168 transform.map( x, y, &tx, &ty );
169
170 geometry.addGeometry( new QgsPoint( tx, ty ) );
171 }
172 }
173}
174
175void QgsGeometryPaintEngine::drawPoints( const QPointF *points, int pointCount )
176{
177 const QTransform transform = painter()->combinedTransform();
178 drawPointsImp( transform, mGeometry, points, pointCount );
179}
180
181void QgsGeometryPaintEngine::drawPoints( const QPoint *points, int pointCount )
182{
183 const QTransform transform = painter()->combinedTransform();
184 drawPointsImp( transform, mGeometry, points, pointCount );
185}
186
187template <typename T>
188void drawRectsImp( const QTransform &transform, QgsGeometryCollection &geometry, const T *rects, int rectCount )
189{
190 geometry.reserve( geometry.numGeometries() + rectCount );
191 if ( transform.isIdentity() )
192 {
193 for ( int i = 0; i < rectCount; ++i, ++rects )
194 {
195 QgsLineString *exterior = new QgsLineString(
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() )
201 },
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() )
207 } );
208 geometry.addGeometry( new QgsPolygon( exterior ) );
209 }
210 }
211 else
212 {
213 for ( int i = 0; i < rectCount; ++i, ++rects )
214 {
215 const double left = rects->left();
216 const double right = rects->right();
217 const double top = rects->top();
218 const double bottom = rects->bottom();
219
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 );
225
226 QgsLineString *exterior = new QgsLineString(
227 QVector<double> { bottomLeftX, bottomRightX, topRightX, topLeftX, bottomLeftX },
228 QVector<double> { bottomLeftY, bottomRightY, topRightY, topLeftY, bottomLeftY } );
229 geometry.addGeometry( new QgsPolygon( exterior ) );
230 }
231 }
232}
233
234void QgsGeometryPaintEngine::drawRects( const QRectF *rects, int rectCount )
235{
236 const QTransform transform = painter()->combinedTransform();
237 drawRectsImp( transform, mGeometry, rects, rectCount );
238}
239
240void QgsGeometryPaintEngine::drawRects( const QRect *rects, int rectCount )
241{
242 const QTransform transform = painter()->combinedTransform();
243 drawRectsImp( transform, mGeometry, rects, rectCount );
244}
245
246template <typename T>
247void drawPolygonImp( const QTransform &transform, QgsGeometryCollection &geometry, const T *points, int pointCount, QPaintEngine::PolygonDrawMode mode, double simplifyTolerance )
248{
249 QVector< double > x;
250 QVector< double > y;
251 x.resize( pointCount );
252 y.resize( pointCount );
253 double *xData = x.data();
254 double *yData = y.data();
255
256 if ( transform.isIdentity() )
257 {
258 for ( int i = 0; i < pointCount; ++i, ++points )
259 {
260 *xData++ = points->x();
261 *yData++ = points->y();
262 }
263 }
264 else
265 {
266 for ( int i = 0; i < pointCount; ++i, ++points )
267 {
268 const double x = points->x();
269 const double y = points->y();
270 double tx, ty;
271 transform.map( x, y, &tx, &ty );
272
273 *xData++ = tx;
274 *yData++ = ty;
275 }
276 }
277
278 switch ( mode )
279 {
280 case QPaintEngine::PolylineMode:
281 if ( simplifyTolerance > 0 )
282 geometry.addGeometry( QgsLineString( x, y ).simplifyByDistance( simplifyTolerance ) );
283 else
284 geometry.addGeometry( new QgsLineString( x, y ) );
285 break;
286
287 case QPaintEngine::OddEvenMode:
288 case QPaintEngine::WindingMode:
289 case QPaintEngine::ConvexMode:
290 if ( simplifyTolerance > 0 )
291 geometry.addGeometry( new QgsPolygon( QgsLineString( x, y ).simplifyByDistance( simplifyTolerance ) ) );
292 else
293 geometry.addGeometry( new QgsPolygon( new QgsLineString( x, y ) ) );
294 break;
295 }
296}
297
298void QgsGeometryPaintEngine::drawPolygon( const QPoint *points, int pointCount, QPaintEngine::PolygonDrawMode mode )
299{
300 if ( mUsePathStroker && mode == PolygonDrawMode::PolylineMode )
301 {
302 // if stroking we have no choice but to go via the QPainterPath route
303 if ( pointCount > 0 )
304 {
305 QPainterPath path;
306 path.moveTo( *points++ );
307 for ( int i = 1; i < pointCount; ++i )
308 {
309 path.lineTo( *points++ );
310 }
311 drawPath( path );
312 }
313 }
314 else
315 {
316 const QTransform transform = painter()->combinedTransform();
317 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
318 }
319}
320
321void QgsGeometryPaintEngine::drawPolygon( const QPointF *points, int pointCount, QPaintEngine::PolygonDrawMode mode )
322{
323 if ( mUsePathStroker )
324 {
325 // if stroking we have no choice but to go via the QPainterPath route
326 if ( pointCount > 0 )
327 {
328 QPainterPath path;
329 path.moveTo( *points++ );
330 for ( int i = 1; i < pointCount; ++i )
331 {
332 path.lineTo( *points++ );
333 }
334 drawPath( path );
335 }
336 }
337 else
338 {
339 const QTransform transform = painter()->combinedTransform();
340 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
341 }
342}
343
344void QgsGeometryPaintEngine::addStrokedLine( const QgsLineString *line, double penWidth, Qgis::EndCapStyle endCapStyle, Qgis::JoinStyle joinStyle, double miterLimit, const QTransform *matrix )
345{
346 std::unique_ptr< QgsAbstractGeometry > buffered;
347 if ( mSimplifyTolerance > 0 )
348 {
349 // For performance, we apply a lower level of simplification to the line BEFORE doing the buffer.
350 // This avoids making the call to GEOS buffer function too expensive, as we'd otherwise be doing it
351 // on the unsimplified line and then immediately discarding most of the detail when we simplify
352 // the resultant buffer.
353 // The 0.75 factor here is just a guess! This could likely be made smarter, eg by considering the pen width?
354 const double preBufferedSimplificationFactor = mSimplifyTolerance * 0.75;
355 std::unique_ptr< QgsLineString > simplified( line->simplifyByDistance( preBufferedSimplificationFactor ) );
356 QgsGeos geos( simplified.get() );
357 buffered.reset( geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
358 }
359 else
360 {
361 QgsGeos geos( line );
362 buffered.reset( geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
363 }
364
365 if ( !buffered )
366 return;
367
368 if ( matrix )
369 buffered->transform( *matrix );
370
371 if ( QgsGeometryCollection *bufferedCollection = qgsgeometry_cast< QgsGeometryCollection * >( buffered.get() ) )
372 {
373 if ( mSimplifyTolerance > 0 )
374 {
375 for ( auto it = bufferedCollection->const_parts_begin(); it != bufferedCollection->const_parts_end(); ++it )
376 {
377 mGeometry.addGeometry( ( *it )->simplifyByDistance( mSimplifyTolerance ) );
378 }
379 }
380 else
381 {
382 mGeometry.addGeometries( bufferedCollection->takeGeometries() );
383 }
384 }
385 else if ( buffered )
386 {
387 if ( mSimplifyTolerance > 0 )
388 {
389 mGeometry.addGeometry( buffered->simplifyByDistance( mSimplifyTolerance ) );
390 }
391 else
392 {
393 mGeometry.addGeometry( buffered.release() );
394 }
395 }
396}
397
398Qgis::EndCapStyle QgsGeometryPaintEngine::penStyleToCapStyle( Qt::PenCapStyle style )
399{
400 switch ( style )
401 {
402 case Qt::FlatCap:
404 case Qt::SquareCap:
406 case Qt::RoundCap:
408 case Qt::MPenCapStyle:
409 // undocumented?
410 break;
411 }
412
414}
415
416Qgis::JoinStyle QgsGeometryPaintEngine::penStyleToJoinStyle( Qt::PenJoinStyle style )
417{
418 switch ( style )
419 {
420 case Qt::MiterJoin:
421 case Qt::SvgMiterJoin:
423 case Qt::BevelJoin:
425 case Qt::RoundJoin:
427 case Qt::MPenJoinStyle:
428 // undocumented?
429 break;
430 }
432}
433
434// based on QPainterPath::toSubpathPolygons()
435void QgsGeometryPaintEngine::addSubpathGeometries( const QPainterPath &path, const QTransform &matrix )
436{
437 if ( path.isEmpty() )
438 return;
439
440 const bool transformIsIdentity = matrix.isIdentity();
441
442 const Qgis::EndCapStyle endCapStyle = penStyleToCapStyle( mPen.capStyle() );
443 const Qgis::JoinStyle joinStyle = penStyleToJoinStyle( mPen.joinStyle() );
444 const double penWidth = mPen.widthF() <= 0 ? 1 : mPen.widthF();
445 const double miterLimit = mPen.miterLimit();
446
447 QVector< double > currentX;
448 QVector< double > currentY;
449 const int count = path.elementCount();
450
451 // polygon parts get queued and post-processed before adding them to the collection
452 std::vector< std::unique_ptr< QgsPolygon > > queuedPolygons;
453
454 for ( int i = 0; i < count; ++i )
455 {
456 const QPainterPath::Element &e = path.elementAt( i );
457 switch ( e.type )
458 {
459 case QPainterPath::MoveToElement:
460 {
461 if ( currentX.size() > 1 )
462 {
463 std::unique_ptr< QgsLineString > line = std::make_unique< QgsLineString >( currentX, currentY );
464 if ( mUsePathStroker )
465 {
466 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ? nullptr : &matrix );
467 }
468 else if ( line->isClosed() )
469 {
470 if ( !transformIsIdentity )
471 line->transform( matrix );
472
473 if ( mSimplifyTolerance > 0 )
474 {
475 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->simplifyByDistance( mSimplifyTolerance ) ) );
476 line.reset();
477 }
478 else
479 {
480 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
481 }
482 }
483 else
484 {
485 if ( !transformIsIdentity )
486 line->transform( matrix );
487 if ( mSimplifyTolerance > 0 )
488 {
489 mGeometry.addGeometry( line->simplifyByDistance( mSimplifyTolerance ) );
490 line.reset();
491 }
492 else
493 {
494 mGeometry.addGeometry( line.release() );
495 }
496 }
497 }
498 currentX.resize( 0 );
499 currentY.resize( 0 );
500
501 currentX.reserve( 16 );
502 currentY.reserve( 16 );
503 currentX << e.x;
504 currentY << e.y;
505 break;
506 }
507
508 case QPainterPath::LineToElement:
509 {
510 currentX << e.x;
511 currentY << e.y;
512 break;
513 }
514
515 case QPainterPath::CurveToElement:
516 {
517 Q_ASSERT( path.elementAt( i + 1 ).type == QPainterPath::CurveToDataElement );
518 Q_ASSERT( path.elementAt( i + 2 ).type == QPainterPath::CurveToDataElement );
519
520 const double x1 = path.elementAt( i - 1 ).x;
521 const double y1 = path.elementAt( i - 1 ).y;
522
523 const double x3 = path.elementAt( i + 1 ).x;
524 const double y3 = path.elementAt( i + 1 ).y;
525
526 const double x4 = path.elementAt( i + 2 ).x;
527 const double y4 = path.elementAt( i + 2 ).y;
528
529 // TODO -- we could likely reduce the number of segmented points here!
530 std::unique_ptr< QgsLineString> bezier( QgsLineString::fromBezierCurve(
531 QgsPoint( x1, y1 ),
532 QgsPoint( e.x, e.y ),
533 QgsPoint( x3, y3 ),
534 QgsPoint( x4, y4 ) ) );
535
536 currentX << bezier->xVector();
537 currentY << bezier->yVector();
538
539 i += 2;
540 break;
541 }
542 case QPainterPath::CurveToDataElement:
543 Q_ASSERT( !"addSubpathGeometries(), bad element type" );
544 break;
545 }
546 }
547
548 if ( currentX.size() > 1 )
549 {
550 std::unique_ptr< QgsLineString > line = std::make_unique< QgsLineString >( currentX, currentY );
551 if ( mUsePathStroker )
552 {
553 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ? nullptr : &matrix );
554 }
555 else if ( line->isClosed() )
556 {
557 if ( !transformIsIdentity )
558 line->transform( matrix );
559 if ( mSimplifyTolerance > 0 )
560 {
561 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->simplifyByDistance( mSimplifyTolerance ) ) );
562 line.reset();
563 }
564 else
565 {
566 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
567 }
568 }
569 else
570 {
571 if ( !transformIsIdentity )
572 line->transform( matrix );
573 if ( mSimplifyTolerance > 0 )
574 {
575 mGeometry.addGeometry( line->simplifyByDistance( mSimplifyTolerance ) );
576 line.reset();
577 }
578 else
579 {
580 mGeometry.addGeometry( line.release() );
581 }
582 }
583 }
584
585 if ( queuedPolygons.empty() )
586 return;
587
588 mGeometry.reserve( static_cast< int >( mGeometry.numGeometries() + queuedPolygons.size() ) );
589
590 QgsMultiPolygon tempMultiPolygon;
591 tempMultiPolygon.reserve( static_cast< int >( queuedPolygons.size() ) );
592 for ( auto &part : queuedPolygons )
593 {
594 tempMultiPolygon.addGeometry( part.release() );
595 }
596
597 // ensure holes are holes, not overlapping polygons
598 QgsGeos geosCollection( &tempMultiPolygon );
599 std::unique_ptr< QgsAbstractGeometry > g = geosCollection.makeValid( Qgis::MakeValidMethod::Linework );
600 if ( !g )
601 return;
602
603 for ( auto it = g->const_parts_begin(); it != g->const_parts_end(); ++it )
604 {
605 mGeometry.addGeometry( ( *it )->clone() );
606 }
607}
608
609void QgsGeometryPaintEngine::drawPath( const QPainterPath &path )
610{
611 const QTransform transform = painter()->combinedTransform();
612 addSubpathGeometries( path, transform );
613}
614
615
616//
617// QgsGeometryPaintDevice
618//
619
621{
622 mPaintEngine = std::make_unique<QgsGeometryPaintEngine>( usePathStroker );
623}
624
626{
627 if ( mPaintEngine )
628 mPaintEngine->setStrokedPathSegments( segments );
629}
630
632{
633 if ( mPaintEngine )
634 mPaintEngine->setSimplificationTolerance( tolerance );
635}
636
638{
639 return mPaintEngine.get();
640}
641
642int QgsGeometryPaintDevice::metric( PaintDeviceMetric m ) const
643{
644 // copy/paste from qpicture.cpp
645 int val;
646
647 switch ( m )
648 {
649 case PdmWidth:
650 val = static_cast< int >( mPaintEngine->geometry().boundingBox().width() );
651 break;
652 case PdmHeight:
653 val = static_cast< int >( mPaintEngine->geometry().boundingBox().height() );
654 break;
655 case PdmWidthMM:
656 val = static_cast< int >( 25.4 / QgsPainting::qtDefaultDpiX() * mPaintEngine->geometry().boundingBox().width() );
657 break;
658 case PdmHeightMM:
659 val = static_cast< int >( 25.4 / QgsPainting::qtDefaultDpiY() * mPaintEngine->geometry().boundingBox().height() );
660 break;
661 case PdmDpiX:
662 case PdmPhysicalDpiX:
664 break;
665 case PdmDpiY:
666 case PdmPhysicalDpiY:
668 break;
669 case PdmNumColors:
670 val = 16777216;
671 break;
672 case PdmDepth:
673 val = 24;
674 break;
675 case PdmDevicePixelRatio:
676 val = 1;
677 break;
678 case PdmDevicePixelRatioScaled:
679 val = static_cast< int >( 1 * QPaintDevice::devicePixelRatioFScale() );
680 break;
681 default:
682 val = 0;
683 qWarning( "QPicture::metric: Invalid metric command" );
684 }
685 return val;
686}
687
689{
690 return mPaintEngine->geometry();
691}
692
694{
696 QPainter painter( &device );
697 painter.drawPath( path );
698 painter.end();
699 return QgsGeometry( device.geometry().clone() );
700}
701
JoinStyle
Join styles for buffers.
Definition qgis.h:2031
@ Bevel
Use beveled joins.
@ Round
Use rounded joins.
@ Miter
Use mitered joins.
EndCapStyle
End cap styles for buffers.
Definition qgis.h:2018
@ Flat
Flat cap (in line with start/end of line)
@ Round
Round cap.
@ 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, and exception handling.
Definition qgsgeos.h:139
Line string geometry type, with support for z-dimension and m-values.
static std::unique_ptr< 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,...
QgsLineString * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
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.
Definition qgspoint.h:49
Polygon geometry type.
Definition qgspolygon.h:33
Contains geos related utilities and functions.
Definition qgsgeos.h:75
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)
Definition qgslogger.h:38