28using namespace Qt::StringLiterals;
35 : QPaintEngine( QPaintEngine::AllFeatures )
36 , mUsePathStroker( usePathStroker )
42 mStrokedPathsSegments = segments;
47 mSimplifyTolerance = tolerance;
62 return QPaintEngine::User;
67 if ( mUsePathStroker && state.state().testFlag( QPaintEngine::DirtyFlag::DirtyPen ) )
76 QgsDebugError( u
"QgsGeometryPaintEngine does not support drawImage method"_s );
82 QgsDebugError( u
"QgsGeometryPaintEngine does not support drawPixmap method"_s );
88 QgsDebugError( u
"QgsGeometryPaintEngine does not support drawTiledPixmap method"_s );
95 if ( transform.isIdentity() )
97 for (
int i = 0; i < lineCount; ++i, ++lines )
100 QVector<double> {
static_cast< double >( lines->x1() ),
static_cast< double >( lines->x2() ) },
101 QVector<double> {
static_cast< double >( lines->y1() ),
static_cast< double >( lines->y2() ) } )
107 for (
int i = 0; i < lineCount; ++i, ++lines )
109 double x1 = lines->x1();
110 double x2 = lines->x2();
111 double y1 = lines->y1();
112 double y2 = lines->y2();
114 double tx1, tx2, ty1, ty2;
115 transform.map( x1, y1, &tx1, &ty1 );
116 transform.map( x2, y2, &tx2, &ty2 );
119 QVector<double> { tx1, tx2 },
120 QVector<double> { ty1, ty2 } )
128 if ( mUsePathStroker )
131 QPaintEngine::drawLines( lines, lineCount );
135 const QTransform transform = painter()->combinedTransform();
142 if ( mUsePathStroker )
145 QPaintEngine::drawLines( lines, lineCount );
149 const QTransform transform = painter()->combinedTransform();
158 if ( transform.isIdentity() )
160 for (
int i = 0; i < pointCount; ++i, ++points )
163 static_cast< double >( points->y() ) ) );
168 for (
int i = 0; i < pointCount; ++i, ++points )
170 double x = points->x();
171 double y = points->y();
174 transform.map( x, y, &tx, &ty );
183 const QTransform transform = painter()->combinedTransform();
189 const QTransform transform = painter()->combinedTransform();
197 if ( transform.isIdentity() )
199 for (
int i = 0; i < rectCount; ++i, ++rects )
202 QVector<double> {
static_cast< double >( rects->left() ),
203 static_cast< double >( rects->right() ),
204 static_cast< double >( rects->right() ),
205 static_cast< double >( rects->left() ),
206 static_cast< double>( rects->left() )
208 QVector<double> {
static_cast< double >( rects->bottom() ),
209 static_cast< double >( rects->bottom() ),
210 static_cast< double >( rects->top() ),
211 static_cast< double >( rects->top() ),
212 static_cast< double >( rects->bottom() )
219 for (
int i = 0; i < rectCount; ++i, ++rects )
221 const double left = rects->left();
222 const double right = rects->right();
223 const double top = rects->top();
224 const double bottom = rects->bottom();
226 double bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, topLeftX, topLeftY, topRightX, topRightY;
227 transform.map( left, bottom, &bottomLeftX, &bottomLeftY );
228 transform.map( right, bottom, &bottomRightX, &bottomRightY );
229 transform.map( left, top, &topLeftX, &topLeftY );
230 transform.map( right, top, &topRightX, &topRightY );
233 QVector<double> { bottomLeftX, bottomRightX, topRightX, topLeftX, bottomLeftX },
234 QVector<double> { bottomLeftY, bottomRightY, topRightY, topLeftY, bottomLeftY } );
242 const QTransform transform = painter()->combinedTransform();
248 const QTransform transform = painter()->combinedTransform();
257 x.resize( pointCount );
258 y.resize( pointCount );
259 double *xData = x.data();
260 double *yData = y.data();
262 if ( transform.isIdentity() )
264 for (
int i = 0; i < pointCount; ++i, ++points )
266 *xData++ = points->x();
267 *yData++ = points->y();
272 for (
int i = 0; i < pointCount; ++i, ++points )
274 const double x = points->x();
275 const double y = points->y();
277 transform.map( x, y, &tx, &ty );
286 case QPaintEngine::PolylineMode:
287 if ( simplifyTolerance > 0 )
293 case QPaintEngine::OddEvenMode:
294 case QPaintEngine::WindingMode:
295 case QPaintEngine::ConvexMode:
296 if ( simplifyTolerance > 0 )
306 if ( mUsePathStroker && mode == PolygonDrawMode::PolylineMode )
309 if ( pointCount > 0 )
312 path.moveTo( *points++ );
313 for (
int i = 1; i < pointCount; ++i )
315 path.lineTo( *points++ );
322 const QTransform transform = painter()->combinedTransform();
323 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
329 if ( mUsePathStroker )
332 if ( pointCount > 0 )
335 path.moveTo( *points++ );
336 for (
int i = 1; i < pointCount; ++i )
338 path.lineTo( *points++ );
345 const QTransform transform = painter()->combinedTransform();
346 drawPolygonImp( transform, mGeometry, points, pointCount, mode, mSimplifyTolerance );
352 std::unique_ptr< QgsAbstractGeometry > buffered;
353 if ( mSimplifyTolerance > 0 )
360 const double preBufferedSimplificationFactor = mSimplifyTolerance * 0.75;
361 std::unique_ptr< QgsLineString > simplified( line->
simplifyByDistance( preBufferedSimplificationFactor ) );
363 buffered.reset(
geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
367 QgsGeos geos( line );
368 buffered.reset( geos.buffer( penWidth / 2, mStrokedPathsSegments, endCapStyle, joinStyle, miterLimit ) );
375 buffered->transform( *matrix );
379 if ( mSimplifyTolerance > 0 )
381 for (
auto it = bufferedCollection->const_parts_begin(); it != bufferedCollection->const_parts_end(); ++it )
383 mGeometry.addGeometry( ( *it )->simplifyByDistance( mSimplifyTolerance ) );
388 mGeometry.addGeometries( bufferedCollection->takeGeometries() );
393 if ( mSimplifyTolerance > 0 )
395 mGeometry.addGeometry( buffered->simplifyByDistance( mSimplifyTolerance ) );
399 mGeometry.addGeometry( buffered.release() );
405void QgsGeometryPaintEngine::addSubpathGeometries(
const QPainterPath &path,
const QTransform &matrix )
407 if ( path.isEmpty() )
410 const bool transformIsIdentity = matrix.isIdentity();
414 const double penWidth = mPen.widthF() <= 0 ? 1 : mPen.widthF();
415 const double miterLimit = mPen.miterLimit();
417 QVector< double > currentX;
418 QVector< double > currentY;
419 const int count = path.elementCount();
422 std::vector< std::unique_ptr< QgsPolygon > > queuedPolygons;
424 for (
int i = 0; i < count; ++i )
426 const QPainterPath::Element &e = path.elementAt( i );
429 case QPainterPath::MoveToElement:
431 if ( currentX.size() > 1 )
433 auto line = std::make_unique< QgsLineString >( currentX, currentY );
434 if ( mUsePathStroker )
436 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
440 if ( !transformIsIdentity )
443 if ( mSimplifyTolerance > 0 )
445 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->
simplifyByDistance( mSimplifyTolerance ) ) );
450 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
455 if ( !transformIsIdentity )
457 if ( mSimplifyTolerance > 0 )
464 mGeometry.addGeometry( line.release() );
468 currentX.resize( 0 );
469 currentY.resize( 0 );
471 currentX.reserve( 16 );
472 currentY.reserve( 16 );
478 case QPainterPath::LineToElement:
485 case QPainterPath::CurveToElement:
487 Q_ASSERT( path.elementAt( i + 1 ).type == QPainterPath::CurveToDataElement );
488 Q_ASSERT( path.elementAt( i + 2 ).type == QPainterPath::CurveToDataElement );
490 const double x1 = path.elementAt( i - 1 ).x;
491 const double y1 = path.elementAt( i - 1 ).y;
493 const double x3 = path.elementAt( i + 1 ).x;
494 const double y3 = path.elementAt( i + 1 ).y;
496 const double x4 = path.elementAt( i + 2 ).x;
497 const double y4 = path.elementAt( i + 2 ).y;
502 QgsPoint( e.x, e.y ),
504 QgsPoint( x4, y4 ) ) );
506 currentX << bezier->xVector();
507 currentY << bezier->yVector();
512 case QPainterPath::CurveToDataElement:
513 Q_ASSERT( !
"addSubpathGeometries(), bad element type" );
518 if ( currentX.size() > 1 )
520 auto line = std::make_unique< QgsLineString >( currentX, currentY );
521 if ( mUsePathStroker )
523 addStrokedLine( line.get(), penWidth, endCapStyle, joinStyle, miterLimit, transformIsIdentity ?
nullptr : &matrix );
527 if ( !transformIsIdentity )
529 if ( mSimplifyTolerance > 0 )
531 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line->
simplifyByDistance( mSimplifyTolerance ) ) );
536 queuedPolygons.emplace_back( std::make_unique< QgsPolygon >( line.release() ) );
541 if ( !transformIsIdentity )
543 if ( mSimplifyTolerance > 0 )
550 mGeometry.addGeometry( line.release() );
555 if ( queuedPolygons.empty() )
558 mGeometry.reserve(
static_cast< int >( mGeometry.numGeometries() + queuedPolygons.size() ) );
560 QgsMultiPolygon tempMultiPolygon;
561 tempMultiPolygon.
reserve(
static_cast< int >( queuedPolygons.size() ) );
562 for (
auto &part : queuedPolygons )
568 QgsGeos geosCollection( &tempMultiPolygon );
573 for (
auto it = g->const_parts_begin(); it != g->const_parts_end(); ++it )
575 mGeometry.addGeometry( ( *it )->clone() );
581 const QTransform transform = painter()->combinedTransform();
582 addSubpathGeometries( path, transform );
592 mPaintEngine = std::make_unique<QgsGeometryPaintEngine>( usePathStroker );
598 mPaintEngine->setStrokedPathSegments( segments );
604 mPaintEngine->setSimplificationTolerance( tolerance );
609 return mPaintEngine.get();
620 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().width() );
623 val =
static_cast< int >( mPaintEngine->geometry().boundingBox().height() );
632 case PdmPhysicalDpiX:
636 case PdmPhysicalDpiY:
645 case PdmDevicePixelRatio:
648 case PdmDevicePixelRatioScaled:
649 val =
static_cast< int >( 1 * QPaintDevice::devicePixelRatioFScale() );
653 qWarning(
"QPicture::metric: Invalid metric command" );
660 return mPaintEngine->geometry();
666 QPainter painter( &device );
667 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)