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