28using namespace Qt::StringLiterals;
35 : QPaintEngine( QPaintEngine::AllFeatures )
36 , mUsePathStroker( usePathStroker )
41 mStrokedPathsSegments = segments;
46 mSimplifyTolerance = tolerance;
61 return QPaintEngine::User;
66 if ( mUsePathStroker && state.state().testFlag( QPaintEngine::DirtyFlag::DirtyPen ) )
75 QgsDebugError( u
"QgsGeometryPaintEngine does not support drawImage method"_s );
81 QgsDebugError( u
"QgsGeometryPaintEngine does not support drawPixmap method"_s );
87 QgsDebugError( u
"QgsGeometryPaintEngine does not support drawTiledPixmap method"_s );
93 if ( transform.isIdentity() )
95 for (
int i = 0; i < lineCount; ++i, ++lines )
98 QVector<double> {
static_cast< double >( lines->x1() ),
static_cast< double >( lines->x2() ) }, QVector<double> {
static_cast< double >( lines->y1() ),
static_cast< double >( lines->y2() ) }
104 for (
int i = 0; i < lineCount; ++i, ++lines )
106 double x1 = lines->x1();
107 double x2 = lines->x2();
108 double y1 = lines->y1();
109 double y2 = lines->y2();
111 double tx1, tx2, ty1, ty2;
112 transform.map( x1, y1, &tx1, &ty1 );
113 transform.map( x2, y2, &tx2, &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();
151 if ( transform.isIdentity() )
153 for (
int i = 0; i < pointCount; ++i, ++points )
155 geometry.
addGeometry(
new QgsPoint(
static_cast< double >( points->x() ),
static_cast< double >( points->y() ) ) );
160 for (
int i = 0; i < pointCount; ++i, ++points )
162 double x = points->x();
163 double y = points->y();
166 transform.map( x, y, &tx, &ty );
175 const QTransform transform = painter()->combinedTransform();
181 const QTransform transform = painter()->combinedTransform();
188 if ( transform.isIdentity() )
190 for (
int i = 0; i < rectCount; ++i, ++rects )
194 static_cast< double >( rects->left() ),
195 static_cast< double >( rects->right() ),
196 static_cast< double >( rects->right() ),
197 static_cast< double >( rects->left() ),
198 static_cast< double>( rects->left() )
201 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() )
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 =
new QgsLineString( QVector<double> { bottomLeftX, bottomRightX, topRightX, topLeftX, bottomLeftX }, QVector<double> { bottomLeftY, bottomRightY, topRightY, topLeftY, bottomLeftY } );
235 const QTransform transform = painter()->combinedTransform();
241 const QTransform transform = painter()->combinedTransform();
245template<
typename T>
void drawPolygonImp(
const QTransform &transform,
QgsGeometryCollection &geometry,
const T *points,
int pointCount, QPaintEngine::PolygonDrawMode mode,
double simplifyTolerance )
249 x.resize( pointCount );
250 y.resize( pointCount );
251 double *xData = x.data();
252 double *yData = y.data();
254 if ( transform.isIdentity() )
256 for (
int i = 0; i < pointCount; ++i, ++points )
258 *xData++ = points->x();
259 *yData++ = points->y();
264 for (
int i = 0; i < pointCount; ++i, ++points )
266 const double x = points->x();
267 const double y = points->y();
269 transform.map( x, y, &tx, &ty );
278 case QPaintEngine::PolylineMode:
279 if ( simplifyTolerance > 0 )
285 case QPaintEngine::OddEvenMode:
286 case QPaintEngine::WindingMode:
287 case QPaintEngine::ConvexMode:
288 if ( simplifyTolerance > 0 )
298 if ( mUsePathStroker && mode == PolygonDrawMode::PolylineMode )
301 if ( pointCount > 0 )
304 path.moveTo( *points++ );
305 for (
int i = 1; i < pointCount; ++i )
307 path.lineTo( *points++ );
314 const QTransform transform = painter()->combinedTransform();
315 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
321 if ( mUsePathStroker )
324 if ( pointCount > 0 )
327 path.moveTo( *points++ );
328 for (
int i = 1; i < pointCount; ++i )
330 path.lineTo( *points++ );
337 const QTransform transform = painter()->combinedTransform();
338 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
344 std::unique_ptr< QgsAbstractGeometry > buffered;
345 if ( mSimplifyTolerance > 0 )
352 const double preBufferedSimplificationFactor = mSimplifyTolerance * 0.75;
353 std::unique_ptr< QgsLineString > simplified( line->
simplifyByDistance( preBufferedSimplificationFactor ) );
355 buffered.reset(
geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
359 QgsGeos geos( line );
360 buffered.reset( geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
367 buffered->transform( *matrix );
371 if ( mSimplifyTolerance > 0 )
373 for (
auto it = bufferedCollection->const_parts_begin(); it != bufferedCollection->const_parts_end(); ++it )
375 mGeometry.addGeometry( ( *it )->simplifyByDistance( mSimplifyTolerance ) );
380 mGeometry.addGeometries( bufferedCollection->takeGeometries() );
385 if ( mSimplifyTolerance > 0 )
387 mGeometry.addGeometry( buffered->simplifyByDistance( mSimplifyTolerance ) );
391 mGeometry.addGeometry( buffered.release() );
397void QgsGeometryPaintEngine::addSubpathGeometries(
const QPainterPath &path,
const QTransform &matrix )
399 if ( path.isEmpty() )
402 const bool transformIsIdentity = matrix.isIdentity();
406 const double penWidth = mPen.widthF() <= 0 ? 1 : mPen.widthF();
407 const double miterLimit = mPen.miterLimit();
409 QVector< double > currentX;
410 QVector< double > currentY;
411 const int count = path.elementCount();
414 std::vector< std::unique_ptr< QgsPolygon > > queuedPolygons;
416 for (
int i = 0; i < count; ++i )
418 const QPainterPath::Element &e = path.elementAt( i );
421 case QPainterPath::MoveToElement:
423 if ( currentX.size() > 1 )
425 auto line = std::make_unique< QgsLineString >( currentX, currentY );
426 if ( mUsePathStroker )
428 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
432 if ( !transformIsIdentity )
435 if ( mSimplifyTolerance > 0 )
437 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->
simplifyByDistance( mSimplifyTolerance ) ) );
442 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
447 if ( !transformIsIdentity )
449 if ( mSimplifyTolerance > 0 )
456 mGeometry.addGeometry( line.release() );
460 currentX.resize( 0 );
461 currentY.resize( 0 );
463 currentX.reserve( 16 );
464 currentY.reserve( 16 );
470 case QPainterPath::LineToElement:
477 case QPainterPath::CurveToElement:
479 Q_ASSERT( path.elementAt( i + 1 ).type == QPainterPath::CurveToDataElement );
480 Q_ASSERT( path.elementAt( i + 2 ).type == QPainterPath::CurveToDataElement );
482 const double x1 = path.elementAt( i - 1 ).x;
483 const double y1 = path.elementAt( i - 1 ).y;
485 const double x3 = path.elementAt( i + 1 ).x;
486 const double y3 = path.elementAt( i + 1 ).y;
488 const double x4 = path.elementAt( i + 2 ).x;
489 const double y4 = path.elementAt( i + 2 ).y;
492 std::unique_ptr< QgsLineString> bezier(
QgsLineString::fromBezierCurve( QgsPoint( x1, y1 ), QgsPoint( e.x, e.y ), QgsPoint( x3, y3 ), QgsPoint( x4, y4 ) ) );
494 currentX << bezier->xVector();
495 currentY << bezier->yVector();
500 case QPainterPath::CurveToDataElement:
501 Q_ASSERT( !
"addSubpathGeometries(), bad element type" );
506 if ( currentX.size() > 1 )
508 auto line = std::make_unique< QgsLineString >( currentX, currentY );
509 if ( mUsePathStroker )
511 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
515 if ( !transformIsIdentity )
517 if ( mSimplifyTolerance > 0 )
519 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->
simplifyByDistance( mSimplifyTolerance ) ) );
524 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
529 if ( !transformIsIdentity )
531 if ( mSimplifyTolerance > 0 )
538 mGeometry.addGeometry( line.release() );
543 if ( queuedPolygons.empty() )
546 mGeometry.reserve(
static_cast< int >( mGeometry.numGeometries() + queuedPolygons.size() ) );
548 QgsMultiPolygon tempMultiPolygon;
549 tempMultiPolygon.
reserve(
static_cast< int >( queuedPolygons.size() ) );
550 for (
auto &part : queuedPolygons )
556 QgsGeos geosCollection( &tempMultiPolygon );
561 for (
auto it = g->const_parts_begin(); it != g->const_parts_end(); ++it )
563 mGeometry.addGeometry( ( *it )->clone() );
569 const QTransform transform = painter()->combinedTransform();
570 addSubpathGeometries( path, transform );
580 mPaintEngine = std::make_unique<QgsGeometryPaintEngine>( usePathStroker );
586 mPaintEngine->setStrokedPathSegments( segments );
592 mPaintEngine->setSimplificationTolerance( tolerance );
597 return mPaintEngine.get();
608 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().width() );
611 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().height() );
620 case PdmPhysicalDpiX:
624 case PdmPhysicalDpiY:
633 case PdmDevicePixelRatio:
636 case PdmDevicePixelRatioScaled:
637 val =
static_cast< int >( 1 * QPaintDevice::devicePixelRatioFScale() );
641 qWarning(
"QPicture::metric: Invalid metric command" );
648 return mPaintEngine->geometry();
654 QPainter painter( &device );
655 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)