31 : QPaintEngine( QPaintEngine::AllFeatures )
32 , mUsePathStroker( usePathStroker )
38 mStrokedPathsSegments = segments;
43 mSimplifyTolerance = tolerance;
58 return QPaintEngine::User;
63 if ( mUsePathStroker && state.state().testFlag( QPaintEngine::DirtyFlag::DirtyPen ) )
88 if ( transform.isIdentity() )
90 for (
int i = 0; i < lineCount; ++i, ++lines )
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() ) } )
100 for (
int i = 0; i < lineCount; ++i, ++lines )
102 double x1 = lines->x1();
103 double x2 = lines->x2();
104 double y1 = lines->y1();
105 double y2 = lines->y2();
107 double tx1, tx2, ty1, ty2;
108 transform.map( x1, y1, &tx1, &ty1 );
109 transform.map( x2, y2, &tx2, &ty2 );
112 QVector<double> { tx1, tx2 },
113 QVector<double> { ty1, ty2 } )
121 if ( mUsePathStroker )
124 QPaintEngine::drawLines( lines, lineCount );
128 const QTransform transform = painter()->combinedTransform();
135 if ( mUsePathStroker )
138 QPaintEngine::drawLines( lines, lineCount );
142 const QTransform transform = painter()->combinedTransform();
151 if ( transform.isIdentity() )
153 for (
int i = 0; i < pointCount; ++i, ++points )
156 static_cast< double >( points->y() ) ) );
161 for (
int i = 0; i < pointCount; ++i, ++points )
163 double x = points->x();
164 double y = points->y();
167 transform.map( x, y, &tx, &ty );
176 const QTransform transform = painter()->combinedTransform();
182 const QTransform transform = painter()->combinedTransform();
190 if ( transform.isIdentity() )
192 for (
int i = 0; i < rectCount; ++i, ++rects )
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() )
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() )
212 for (
int i = 0; i < rectCount; ++i, ++rects )
214 const double left = rects->left();
215 const double right = rects->right();
216 const double top = rects->top();
217 const double bottom = rects->bottom();
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 );
226 QVector<double> { bottomLeftX, bottomRightX, topRightX, topLeftX, bottomLeftX },
227 QVector<double> { bottomLeftY, bottomRightY, topRightY, topLeftY, bottomLeftY } );
235 const QTransform transform = painter()->combinedTransform();
241 const QTransform transform = painter()->combinedTransform();
250 x.resize( pointCount );
251 y.resize( pointCount );
252 double *xData = x.data();
253 double *yData = y.data();
255 if ( transform.isIdentity() )
257 for (
int i = 0; i < pointCount; ++i, ++points )
259 *xData++ = points->x();
260 *yData++ = points->y();
265 for (
int i = 0; i < pointCount; ++i, ++points )
267 const double x = points->x();
268 const double y = points->y();
270 transform.map( x, y, &tx, &ty );
279 case QPaintEngine::PolylineMode:
280 if ( simplifyTolerance > 0 )
286 case QPaintEngine::OddEvenMode:
287 case QPaintEngine::WindingMode:
288 case QPaintEngine::ConvexMode:
289 if ( simplifyTolerance > 0 )
299 if ( mUsePathStroker && mode == PolygonDrawMode::PolylineMode )
302 if ( pointCount > 0 )
305 path.moveTo( *points++ );
306 for (
int i = 1; i < pointCount; ++i )
308 path.lineTo( *points++ );
315 const QTransform transform = painter()->combinedTransform();
316 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
322 if ( mUsePathStroker )
325 if ( pointCount > 0 )
328 path.moveTo( *points++ );
329 for (
int i = 1; i < pointCount; ++i )
331 path.lineTo( *points++ );
338 const QTransform transform = painter()->combinedTransform();
339 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
345 std::unique_ptr< QgsAbstractGeometry > buffered;
346 if ( mSimplifyTolerance > 0 )
353 const double preBufferedSimplificationFactor = mSimplifyTolerance * 0.75;
354 std::unique_ptr< QgsLineString > simplified( line->
simplifyByDistance( preBufferedSimplificationFactor ) );
356 buffered.reset(
geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
361 buffered.reset(
geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
368 buffered->transform( *matrix );
370 if (
QgsGeometryCollection *bufferedCollection = qgsgeometry_cast< QgsGeometryCollection * >( buffered.get() ) )
372 if ( mSimplifyTolerance > 0 )
374 for (
auto it = bufferedCollection->const_parts_begin(); it != bufferedCollection->const_parts_end(); ++it )
376 mGeometry.
addGeometry( ( *it )->simplifyByDistance( mSimplifyTolerance ) );
381 mGeometry.
addGeometries( bufferedCollection->takeGeometries() );
386 if ( mSimplifyTolerance > 0 )
388 mGeometry.
addGeometry( buffered->simplifyByDistance( mSimplifyTolerance ) );
397Qgis::EndCapStyle QgsGeometryPaintEngine::penStyleToCapStyle( Qt::PenCapStyle style )
407 case Qt::MPenCapStyle:
415Qgis::JoinStyle QgsGeometryPaintEngine::penStyleToJoinStyle( Qt::PenJoinStyle style )
420 case Qt::SvgMiterJoin:
426 case Qt::MPenJoinStyle:
434void QgsGeometryPaintEngine::addSubpathGeometries(
const QPainterPath &path,
const QTransform &matrix )
436 if ( path.isEmpty() )
439 const bool transformIsIdentity = matrix.isIdentity();
442 const Qgis::JoinStyle joinStyle = penStyleToJoinStyle( mPen.joinStyle() );
443 const double penWidth = mPen.widthF() <= 0 ? 1 : mPen.widthF();
444 const double miterLimit = mPen.miterLimit();
446 QVector< double > currentX;
447 QVector< double > currentY;
448 const int count = path.elementCount();
451 std::vector< std::unique_ptr< QgsPolygon > > queuedPolygons;
453 for (
int i = 0; i < count; ++i )
455 const QPainterPath::Element &e = path.elementAt( i );
458 case QPainterPath::MoveToElement:
460 if ( currentX.size() > 1 )
462 std::unique_ptr< QgsLineString > line = std::make_unique< QgsLineString >( currentX, currentY );
463 if ( mUsePathStroker )
465 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
467 else if ( line->isClosed() )
469 if ( !transformIsIdentity )
470 line->transform( matrix );
472 if ( mSimplifyTolerance > 0 )
474 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->simplifyByDistance( mSimplifyTolerance ) ) );
479 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
484 if ( !transformIsIdentity )
485 line->transform( matrix );
486 if ( mSimplifyTolerance > 0 )
488 mGeometry.
addGeometry( line->simplifyByDistance( mSimplifyTolerance ) );
497 currentX.resize( 0 );
498 currentY.resize( 0 );
500 currentX.reserve( 16 );
501 currentY.reserve( 16 );
507 case QPainterPath::LineToElement:
514 case QPainterPath::CurveToElement:
516 Q_ASSERT( path.elementAt( i + 1 ).type == QPainterPath::CurveToDataElement );
517 Q_ASSERT( path.elementAt( i + 2 ).type == QPainterPath::CurveToDataElement );
519 const double x1 = path.elementAt( i - 1 ).x;
520 const double y1 = path.elementAt( i - 1 ).y;
522 const double x3 = path.elementAt( i + 1 ).x;
523 const double y3 = path.elementAt( i + 1 ).y;
525 const double x4 = path.elementAt( i + 2 ).x;
526 const double y4 = path.elementAt( i + 2 ).y;
535 currentX << bezier->xVector();
536 currentY << bezier->yVector();
541 case QPainterPath::CurveToDataElement:
542 Q_ASSERT( !
"addSubpathGeometries(), bad element type" );
547 if ( currentX.size() > 1 )
549 std::unique_ptr< QgsLineString > line = std::make_unique< QgsLineString >( currentX, currentY );
550 if ( mUsePathStroker )
552 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
554 else if ( line->isClosed() )
556 if ( !transformIsIdentity )
557 line->transform( matrix );
558 if ( mSimplifyTolerance > 0 )
560 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->simplifyByDistance( mSimplifyTolerance ) ) );
565 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
570 if ( !transformIsIdentity )
571 line->transform( matrix );
572 if ( mSimplifyTolerance > 0 )
574 mGeometry.
addGeometry( line->simplifyByDistance( mSimplifyTolerance ) );
584 if ( queuedPolygons.empty() )
590 tempMultiPolygon.
reserve(
static_cast< int >( queuedPolygons.size() ) );
591 for (
auto &part : queuedPolygons )
597 QgsGeos geosCollection( &tempMultiPolygon );
602 for (
auto it = g->const_parts_begin(); it != g->const_parts_end(); ++it )
610 const QTransform transform = painter()->combinedTransform();
611 addSubpathGeometries( path, transform );
620 mPaintEngine = std::make_unique<QgsGeometryPaintEngine>( usePathStroker );
626 mPaintEngine->setStrokedPathSegments( segments );
632 mPaintEngine->setSimplificationTolerance( tolerance );
637 return mPaintEngine.get();
648 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().width() );
651 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().height() );
654 val =
static_cast< int >( 25.4 /
qt_defaultDpiX() * mPaintEngine->geometry().boundingBox().width() );
657 val =
static_cast< int >( 25.4 /
qt_defaultDpiY() * mPaintEngine->geometry().boundingBox().height() );
660 case PdmPhysicalDpiX:
664 case PdmPhysicalDpiY:
673 case PdmDevicePixelRatio:
676 case PdmDevicePixelRatioScaled:
677 val =
static_cast< int >( 1 * QPaintDevice::devicePixelRatioFScale() );
681 qWarning(
"QPicture::metric: Invalid metric command" );
688 return mPaintEngine->geometry();
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.
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*.
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.
Contains geos related utilities and functions.
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()