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 ) )
72 QgsDebugError( QStringLiteral(
"QgsGeometryPaintEngine does not support drawImage method" ) );
78 QgsDebugError( QStringLiteral(
"QgsGeometryPaintEngine does not support drawPixmap method" ) );
84 QgsDebugError( QStringLiteral(
"QgsGeometryPaintEngine does not support drawTiledPixmap method" ) );
91 if ( transform.isIdentity() )
93 for (
int i = 0; i < lineCount; ++i, ++lines )
96 QVector<double> {
static_cast< double >( lines->x1() ),
static_cast< double >( lines->x2() ) },
97 QVector<double> {
static_cast< double >( lines->y1() ),
static_cast< double >( lines->y2() ) } )
103 for (
int i = 0; i < lineCount; ++i, ++lines )
105 double x1 = lines->x1();
106 double x2 = lines->x2();
107 double y1 = lines->y1();
108 double y2 = lines->y2();
110 double tx1, tx2, ty1, ty2;
111 transform.map( x1, y1, &tx1, &ty1 );
112 transform.map( x2, y2, &tx2, &ty2 );
115 QVector<double> { tx1, tx2 },
116 QVector<double> { ty1, ty2 } )
124 if ( mUsePathStroker )
127 QPaintEngine::drawLines( lines, lineCount );
131 const QTransform transform = painter()->combinedTransform();
138 if ( mUsePathStroker )
141 QPaintEngine::drawLines( lines, lineCount );
145 const QTransform transform = painter()->combinedTransform();
154 if ( transform.isIdentity() )
156 for (
int i = 0; i < pointCount; ++i, ++points )
159 static_cast< double >( points->y() ) ) );
164 for (
int i = 0; i < pointCount; ++i, ++points )
166 double x = points->x();
167 double y = points->y();
170 transform.map( x, y, &tx, &ty );
179 const QTransform transform = painter()->combinedTransform();
185 const QTransform transform = painter()->combinedTransform();
193 if ( transform.isIdentity() )
195 for (
int i = 0; i < rectCount; ++i, ++rects )
198 QVector<double> {
static_cast< double >( rects->left() ),
199 static_cast< double >( rects->right() ),
200 static_cast< double >( rects->right() ),
201 static_cast< double >( rects->left() ),
202 static_cast< double>( rects->left() )
204 QVector<double> {
static_cast< double >( rects->bottom() ),
205 static_cast< double >( rects->bottom() ),
206 static_cast< double >( rects->top() ),
207 static_cast< double >( rects->top() ),
208 static_cast< double >( rects->bottom() )
215 for (
int i = 0; i < rectCount; ++i, ++rects )
217 const double left = rects->left();
218 const double right = rects->right();
219 const double top = rects->top();
220 const double bottom = rects->bottom();
222 double bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, topLeftX, topLeftY, topRightX, topRightY;
223 transform.map( left, bottom, &bottomLeftX, &bottomLeftY );
224 transform.map( right, bottom, &bottomRightX, &bottomRightY );
225 transform.map( left, top, &topLeftX, &topLeftY );
226 transform.map( right, top, &topRightX, &topRightY );
229 QVector<double> { bottomLeftX, bottomRightX, topRightX, topLeftX, bottomLeftX },
230 QVector<double> { bottomLeftY, bottomRightY, topRightY, topLeftY, bottomLeftY } );
238 const QTransform transform = painter()->combinedTransform();
244 const QTransform transform = painter()->combinedTransform();
253 x.resize( pointCount );
254 y.resize( pointCount );
255 double *xData = x.data();
256 double *yData = y.data();
258 if ( transform.isIdentity() )
260 for (
int i = 0; i < pointCount; ++i, ++points )
262 *xData++ = points->x();
263 *yData++ = points->y();
268 for (
int i = 0; i < pointCount; ++i, ++points )
270 const double x = points->x();
271 const double y = points->y();
273 transform.map( x, y, &tx, &ty );
282 case QPaintEngine::PolylineMode:
283 if ( simplifyTolerance > 0 )
289 case QPaintEngine::OddEvenMode:
290 case QPaintEngine::WindingMode:
291 case QPaintEngine::ConvexMode:
292 if ( simplifyTolerance > 0 )
302 if ( mUsePathStroker && mode == PolygonDrawMode::PolylineMode )
305 if ( pointCount > 0 )
308 path.moveTo( *points++ );
309 for (
int i = 1; i < pointCount; ++i )
311 path.lineTo( *points++ );
318 const QTransform transform = painter()->combinedTransform();
319 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
325 if ( mUsePathStroker )
328 if ( pointCount > 0 )
331 path.moveTo( *points++ );
332 for (
int i = 1; i < pointCount; ++i )
334 path.lineTo( *points++ );
341 const QTransform transform = painter()->combinedTransform();
342 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
348 std::unique_ptr< QgsAbstractGeometry > buffered;
349 if ( mSimplifyTolerance > 0 )
356 const double preBufferedSimplificationFactor = mSimplifyTolerance * 0.75;
357 std::unique_ptr< QgsLineString > simplified( line->
simplifyByDistance( preBufferedSimplificationFactor ) );
359 buffered.reset(
geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
363 QgsGeos geos( line );
364 buffered.reset( geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
371 buffered->transform( *matrix );
375 if ( mSimplifyTolerance > 0 )
377 for (
auto it = bufferedCollection->const_parts_begin(); it != bufferedCollection->const_parts_end(); ++it )
379 mGeometry.addGeometry( ( *it )->simplifyByDistance( mSimplifyTolerance ) );
384 mGeometry.addGeometries( bufferedCollection->takeGeometries() );
389 if ( mSimplifyTolerance > 0 )
391 mGeometry.addGeometry( buffered->simplifyByDistance( mSimplifyTolerance ) );
395 mGeometry.addGeometry( buffered.release() );
401void QgsGeometryPaintEngine::addSubpathGeometries(
const QPainterPath &path,
const QTransform &matrix )
403 if ( path.isEmpty() )
406 const bool transformIsIdentity = matrix.isIdentity();
410 const double penWidth = mPen.widthF() <= 0 ? 1 : mPen.widthF();
411 const double miterLimit = mPen.miterLimit();
413 QVector< double > currentX;
414 QVector< double > currentY;
415 const int count = path.elementCount();
418 std::vector< std::unique_ptr< QgsPolygon > > queuedPolygons;
420 for (
int i = 0; i < count; ++i )
422 const QPainterPath::Element &e = path.elementAt( i );
425 case QPainterPath::MoveToElement:
427 if ( currentX.size() > 1 )
429 auto line = std::make_unique< QgsLineString >( currentX, currentY );
430 if ( mUsePathStroker )
432 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
436 if ( !transformIsIdentity )
439 if ( mSimplifyTolerance > 0 )
441 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->
simplifyByDistance( mSimplifyTolerance ) ) );
446 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
451 if ( !transformIsIdentity )
453 if ( mSimplifyTolerance > 0 )
460 mGeometry.addGeometry( line.release() );
464 currentX.resize( 0 );
465 currentY.resize( 0 );
467 currentX.reserve( 16 );
468 currentY.reserve( 16 );
474 case QPainterPath::LineToElement:
481 case QPainterPath::CurveToElement:
483 Q_ASSERT( path.elementAt( i + 1 ).type == QPainterPath::CurveToDataElement );
484 Q_ASSERT( path.elementAt( i + 2 ).type == QPainterPath::CurveToDataElement );
486 const double x1 = path.elementAt( i - 1 ).x;
487 const double y1 = path.elementAt( i - 1 ).y;
489 const double x3 = path.elementAt( i + 1 ).x;
490 const double y3 = path.elementAt( i + 1 ).y;
492 const double x4 = path.elementAt( i + 2 ).x;
493 const double y4 = path.elementAt( i + 2 ).y;
498 QgsPoint( e.x, e.y ),
500 QgsPoint( x4, y4 ) ) );
502 currentX << bezier->xVector();
503 currentY << bezier->yVector();
508 case QPainterPath::CurveToDataElement:
509 Q_ASSERT( !
"addSubpathGeometries(), bad element type" );
514 if ( currentX.size() > 1 )
516 auto line = std::make_unique< QgsLineString >( currentX, currentY );
517 if ( mUsePathStroker )
519 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
523 if ( !transformIsIdentity )
525 if ( mSimplifyTolerance > 0 )
527 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->
simplifyByDistance( mSimplifyTolerance ) ) );
532 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
537 if ( !transformIsIdentity )
539 if ( mSimplifyTolerance > 0 )
546 mGeometry.addGeometry( line.release() );
551 if ( queuedPolygons.empty() )
554 mGeometry.reserve(
static_cast< int >( mGeometry.numGeometries() + queuedPolygons.size() ) );
556 QgsMultiPolygon tempMultiPolygon;
557 tempMultiPolygon.
reserve(
static_cast< int >( queuedPolygons.size() ) );
558 for (
auto &part : queuedPolygons )
564 QgsGeos geosCollection( &tempMultiPolygon );
569 for (
auto it = g->const_parts_begin(); it != g->const_parts_end(); ++it )
571 mGeometry.addGeometry( ( *it )->clone() );
577 const QTransform transform = painter()->combinedTransform();
578 addSubpathGeometries( path, transform );
588 mPaintEngine = std::make_unique<QgsGeometryPaintEngine>( usePathStroker );
594 mPaintEngine->setStrokedPathSegments( segments );
600 mPaintEngine->setSimplificationTolerance( tolerance );
605 return mPaintEngine.get();
616 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().width() );
619 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().height() );
628 case PdmPhysicalDpiX:
632 case PdmPhysicalDpiY:
641 case PdmDevicePixelRatio:
644 case PdmDevicePixelRatioScaled:
645 val =
static_cast< int >( 1 * QPaintDevice::devicePixelRatioFScale() );
649 qWarning(
"QPicture::metric: Invalid metric command" );
656 return mPaintEngine->geometry();
662 QPainter painter( &device );
663 painter.drawPath( path );
JoinStyle
Join styles for buffers.
EndCapStyle
End cap styles for buffers.
@ 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 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
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.
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,...
bool isClosed() const override
Returns true if the curve is closed.
QgsLineString * simplifyByDistance(double tolerance) const override
Simplifies the geometry by applying the Douglas Peucker simplification by distance algorithm.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
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.
static Qgis::EndCapStyle penCapStyleToEndCapStyle(Qt::PenCapStyle style)
Converts a Qt pen cap style to a QGIS end cap style.
static Qgis::JoinStyle penJoinStyleToJoinStyle(Qt::PenJoinStyle style)
Converts a Qt pen joinstyle to a QGIS join style.
Contains geos related utilities and functions.
T qgsgeometry_cast(QgsAbstractGeometry *geom)
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)