File indexing completed on 2025-01-05 03:59:16
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2008-2009 Torsten Rahn <tackat@kde.org> 0004 // 0005 0006 #ifndef MARBLE_GEOPAINTER_H 0007 #define MARBLE_GEOPAINTER_H 0008 0009 0010 #include "digikam_export.h" 0011 0012 // Marble 0013 #include "MarbleGlobal.h" 0014 #include "ClipPainter.h" 0015 0016 #include <QSizeF> 0017 0018 class QImage; 0019 class QPaintDevice; 0020 class QRegion; 0021 class QString; 0022 0023 namespace Marble 0024 { 0025 0026 class ViewportParams; 0027 class GeoPainterPrivate; 0028 class GeoDataCoordinates; 0029 class GeoDataLineString; 0030 class GeoDataLinearRing; 0031 class GeoDataPoint; 0032 class GeoDataPolygon; 0033 0034 0035 /*! 0036 \class GeoPainter 0037 \brief A painter that allows to draw geometric primitives on the map. 0038 0039 This class allows application developers to draw simple geometric shapes 0040 and objects onto the map. 0041 0042 The API is modeled after the QPainter API. 0043 0044 The GeoPainter provides a wide range of methods that are using geographic 0045 ("geodesic") coordinates to position the item. 0046 For example a point or the nodes of a polygon can fully be described in 0047 geographic coordinates. 0048 0049 In all these cases the position of the object is specified in geographic 0050 coordinates. 0051 0052 There are however some cases where there are two viable cases: 0053 \li the shape of the object could still use screen coordinates (like a label 0054 or an icon). 0055 \li Alternatively the shape of the object can get projected according 0056 to the current projection (e.g. a texture projected onto the spherical 0057 surface) 0058 0059 If screen coordinates are used then e.g. width and height are assumed to be 0060 expressed in pixels, otherwise degrees are used. 0061 0062 Painter transformations (e.g. translate) always happen in screen 0063 coordinates. 0064 0065 Like in QPainter drawing objects onto a widget should always considered to 0066 be a volatile operation. This means that e.g. placemarks don't get added to 0067 the globe permanently. 0068 So the drawing needs to be done on every repaint to prevent that drawings 0069 will disappear during the next paint event. 0070 0071 So if you want to add placemarks to your map widget permanently (i.e. you 0072 don't want to take care of repainting) then you need to use other solutions 0073 such as the KML import of the Marble framework or Marble's GeoGraphicsItems. 0074 0075 \note By default the GeoPainter automatically filters geographical content 0076 in order to provide fast painting: 0077 \li Geographically positioned objects which are outside the viewport are not 0078 drawn at all. 0079 Parts of objects which are specified through geographic coordinates 0080 (like polygons, ellipses etc.) get cut off if they are not placed within the 0081 viewport. 0082 \li Objects which have a shape that is specified through geographic 0083 coordinates get filtered according to the viewport resolution: 0084 If the object is much smaller than a pixel then it won't get drawn at all. 0085 */ 0086 0087 0088 class DIGIKAM_EXPORT GeoPainter : public ClipPainter 0089 { 0090 public: 0091 enum Frame { 0092 NoOptions = 0x0, 0093 RoundFrame = 0x1 0094 }; 0095 0096 Q_DECLARE_FLAGS(Frames, Frame) 0097 0098 /*! 0099 \brief Creates a new geo painter. 0100 0101 To create a geo painter it's necessary to provide \a paintDevice 0102 as a canvas and the viewportParams to specify the map projection 0103 inside the viewport. 0104 */ 0105 GeoPainter( QPaintDevice * paintDevice, 0106 const ViewportParams *viewportParams, 0107 MapQuality mapQuality = NormalQuality ); 0108 0109 0110 /*! 0111 \brief Destroys the geo painter. 0112 */ 0113 ~GeoPainter(); 0114 0115 0116 /*! 0117 \brief Returns the map quality. 0118 \return The map quality that got assigned to the painter. 0119 */ 0120 MapQuality mapQuality() const; 0121 0122 0123 /*! 0124 \brief Draws a text annotation that points to a geodesic position. 0125 0126 The annotation consists of a bubble with the specified \a text inside. 0127 By choosing an appropriate pen for the painter it's possible to change 0128 the color and line style of the bubble outline and the text. The brush 0129 chosen for the painter is used to paint the background of the bubble 0130 0131 The optional parameters which describe the layout of the bubble are 0132 similar to those used by QPainter::drawRoundedRect(). 0133 Unlike in QPainter the rounded corners are not specified in percentage 0134 but in pixels to provide for optimal aesthetics. 0135 By choosing a positive or negative bubbleOffset it's possible to 0136 place the annotation on top, bottom, left or right of the annotated 0137 position. 0138 0139 \param position The geodesic position 0140 \param text The text contained by the bubble 0141 \param bubbleSize The size of the bubble that holds the annotation text. 0142 A height of 0 can be used to have the height calculated 0143 automatically to fit the needed text height. 0144 \param bubbleOffsetX The x-axis offset between the annotated position and 0145 the "root" of the speech bubble's "arrow". 0146 \param bubbleOffsetY The y-axis offset between the annotated position and 0147 the "root" of the speech bubble's "arrow". 0148 \param xRnd Specifies the geometry of the rounded corners in pixels along 0149 the x-axis. 0150 \param yRnd Specifies the geometry of the rounded corners in pixels along 0151 the y-axis. 0152 0153 \see GeoDataCoordinates 0154 */ 0155 void drawAnnotation( const GeoDataCoordinates & position, 0156 const QString & text, 0157 QSizeF bubbleSize = QSizeF( 130, 100 ), 0158 qreal bubbleOffsetX = -10, qreal bubbleOffsetY = -30, 0159 qreal xRnd = 5, qreal yRnd = 5 ); 0160 0161 0162 /*! 0163 \brief Draws a single point at a given geographic position. 0164 The point is drawn using the painter's pen color. 0165 0166 \see GeoDataCoordinates 0167 */ 0168 void drawPoint ( const GeoDataCoordinates & position ); 0169 0170 0171 /*! 0172 \brief Creates a region for a given geographic position. 0173 0174 A QRegion object is created that represents the area covered by 0175 GeoPainter::drawPoint( GeoDataCoordinates ). It can be used e.g. for 0176 input event handling of objects that have been painted using 0177 GeoPainter::drawPoint( GeoDataCoordinates ). 0178 0179 The width allows to set the "stroke width" for the region. For input 0180 event handling it's always advisable to use a width that is slightly 0181 bigger than the width of the painter's pen. 0182 0183 \see GeoDataCoordinates 0184 */ 0185 QRegion regionFromPoint ( const GeoDataCoordinates & position, 0186 qreal strokeWidth = 3) const; 0187 0188 0189 /*! 0190 \brief Draws a single point at a given geographic position. 0191 The point is drawn using the painter's pen color. 0192 0193 \see GeoDataPoint 0194 */ 0195 void drawPoint ( const GeoDataPoint & point ); 0196 0197 0198 /*! 0199 \brief Create a region for a given geographic position. 0200 0201 A QRegion object is created that represents the area covered by 0202 GeoPainter::drawPoint( GeoDataPoint ). It can be used e.g. for 0203 input event handling of objects that have been painted using 0204 GeoPainter::drawPoint( GeoDataPoint ). 0205 0206 The width allows to set the "stroke width" for the region. For input 0207 event handling it's always advisable to use a width that is slightly 0208 bigger than the width of the painter's pen. 0209 */ 0210 QRegion regionFromPoint ( const GeoDataPoint & point, 0211 qreal strokeWidth = 3) const; 0212 0213 0214 /*! 0215 \brief Draws the given text at a given geographic position. 0216 The \a text is drawn starting at the given \a position using the painter's 0217 font property. The text rendering is performed in screen coordinates and is 0218 not subject to the current projection. 0219 An offset given in screenPixels can be provided via xOffset and yOffset 0220 in order to tweak the text position. 0221 By optionally adding a width, height and text options the text flow can be 0222 further influenced. 0223 */ 0224 void drawText ( const GeoDataCoordinates & position, const QString & text, 0225 qreal xOffset = 0.0, qreal yOffset = 0.0, 0226 qreal width = 0.0, qreal height = 0.0, 0227 const QTextOption & option = QTextOption() ); 0228 0229 0230 /*! 0231 \brief Draws an ellipse at the given position. 0232 The ellipse is placed with its center located at the given \a centerPosition. 0233 0234 For the outline it uses the painter's pen and for the background the 0235 painter's brush. 0236 0237 If \a isGeoProjected is true then the outline of the ellipse is drawn 0238 in geographic coordinates. In this case the \a width and the \a height 0239 are interpreted to be degrees. 0240 If \a isGeoProjected is false then the outline of the ellipse is drawn 0241 in screen coordinates. In this case the \a width and the \a height 0242 are interpreted to be pixels. 0243 0244 \see GeoDataCoordinates 0245 */ 0246 void drawEllipse ( const GeoDataCoordinates & centerPosition, 0247 qreal width, qreal height, bool isGeoProjected = false ); 0248 0249 0250 /*! 0251 \brief Creates a region for an ellipse at a given position 0252 0253 A QRegion object is created that represents the area covered by 0254 GeoPainter::drawEllipse(). As such it can be used e.g. for input event 0255 handling for objects that have been painted using GeoPainter::drawEllipse(). 0256 0257 The \a strokeWidth allows to extrude the QRegion by half the amount of 0258 "stroke width" pixels. For input event handling it's always advisable to use 0259 a width that is slightly bigger than the width of the painter's pen. 0260 0261 \see GeoDataCoordinates 0262 */ 0263 QRegion regionFromEllipse ( const GeoDataCoordinates & centerPosition, 0264 qreal width, qreal height, bool isGeoProjected = false, 0265 qreal strokeWidth = 3 ) const; 0266 0267 0268 /*! 0269 \brief Draws an image at the given position. 0270 The image is placed with its center located at the given \a centerPosition. 0271 0272 The image rendering is performed in screen coordinates and is 0273 not subject to the current projection. 0274 0275 \see GeoDataCoordinates 0276 */ 0277 void drawImage ( const GeoDataCoordinates & centerPosition, 0278 const QImage & image /* , bool isGeoProjected = false */ ); 0279 0280 0281 /*! 0282 \brief Draws a pixmap at the given position. 0283 The pixmap is placed with its center located at the given \a centerPosition. 0284 0285 The image rendering is performed in screen coordinates and is 0286 not subject to the current projection. 0287 0288 \see GeoDataCoordinates 0289 */ 0290 void drawPixmap ( const GeoDataCoordinates & centerPosition, 0291 const QPixmap & pixmap /*, bool isGeoProjected = false */ ); 0292 0293 /*! 0294 \brief Creates a region for a rectangle for a pixmap at a given position. 0295 0296 A QRegion object is created that represents the area covered by 0297 GeoPainter::drawPixmap(). This can be used e.g. for input event handling 0298 for objects that have been painted using GeoPainter::drawPixmap(). 0299 0300 The \a margin allows to extrude the QRegion by "margin" pixels on every side. 0301 0302 \see GeoDataCoordinates 0303 */ 0304 QRegion regionFromPixmapRect(const GeoDataCoordinates ¢erCoordinates, 0305 int width, int height, 0306 int margin = 0) const; 0307 0308 /*! 0309 \brief Helper method for safe and quick linestring conversion. 0310 0311 In general drawPolyline() should be used instead. However 0312 in situations where the same linestring is supposed to be 0313 drawn multiple times it's a good idea to cache the 0314 screen polygons using this method. 0315 0316 \see GeoDataLineString 0317 */ 0318 void polygonsFromLineString( const GeoDataLineString &lineString, 0319 QVector<QPolygonF*> &polygons) const; 0320 0321 0322 /*! 0323 \brief Draws a given line string (a "polyline") with a label. 0324 0325 The \a lineString is drawn using the current pen. It's possible to 0326 provide a \a labelText for the \a lineString. The text is rendered using 0327 the painter's font property. 0328 The position of the \a labelText can be specified using the 0329 \a labelPositionFlags. 0330 0331 \see GeoDataLineString 0332 */ 0333 void drawPolyline ( const GeoDataLineString & lineString, 0334 const QString& labelText, 0335 LabelPositionFlags labelPositionFlags = LineCenter, 0336 const QColor& labelcolor = Qt::black); 0337 0338 /*! 0339 \brief Draws Labels for a given set of screen polygons. 0340 0341 In common cases the drawPolyline overload can be used instead. 0342 However in certain more complex cases this particular method 0343 might be helpful for further optimization. 0344 */ 0345 0346 void drawLabelsForPolygons( const QVector<QPolygonF*> &polygons, 0347 const QString& labelText, 0348 LabelPositionFlags labelPositionFlags, 0349 const QColor& labelColor ); 0350 0351 /*! 0352 \brief Draws a given line string (a "polyline"). 0353 0354 The \a lineString is drawn using the current pen. 0355 0356 \see GeoDataLineString 0357 */ 0358 void drawPolyline(const GeoDataLineString & lineString); 0359 0360 /*! 0361 \brief Creates a region for a given line string (a "polyline"). 0362 0363 A QRegion object is created that represents the area covered by 0364 GeoPainter::drawPolyline( GeoDataLineString ). As such it can be used 0365 e.g. for input event handling for objects that have been painted using 0366 GeoPainter::drawPolyline( GeoDataLineString ). 0367 0368 The \a strokeWidth allows to extrude the QRegion by half the amount of 0369 "stroke width" pixels. For input event handling it's always advisable to use 0370 a width that is slightly bigger than the width of the painter's pen. 0371 0372 \see GeoDataLineString 0373 */ 0374 QRegion regionFromPolyline ( const GeoDataLineString & lineString, 0375 qreal strokeWidth = 3 ) const; 0376 0377 0378 /*! 0379 \brief Draws a given linear ring (a "polygon without holes"). 0380 0381 The outline of the \a linearRing is drawn using the current pen. The 0382 background is painted using the current brush of the painter. 0383 Like in QPainter::drawPolygon() the \a fillRule specifies the 0384 fill algorithm that is used to fill the polygon. 0385 0386 \see GeoDataLinearRing 0387 */ 0388 void drawPolygon ( const GeoDataLinearRing & linearRing, 0389 Qt::FillRule fillRule = Qt::OddEvenFill ); 0390 0391 0392 /*! 0393 \brief Creates a region for a given linear ring (a "polygon without holes"). 0394 0395 A QRegion object is created that represents the area covered by 0396 GeoPainter::drawPolygon( GeoDataLinearRing ). As such it can be used 0397 e.g. for input event handling for objects that have been painted using 0398 GeoPainter::drawPolygon( GeoDataLinearRing ). 0399 0400 Like in drawPolygon() the \a fillRule specifies the fill algorithm that is 0401 used to fill the polygon. 0402 0403 The \a strokeWidth allows to extrude the QRegion by half the amount of 0404 "stroke width" pixels. For input event handling it's always advisable to use 0405 a width that is slightly bigger than the width of the painter's pen. 0406 0407 For the polygon case a "cosmetic" strokeWidth of zero should provide the 0408 best performance. 0409 0410 \see GeoDataLinearRing 0411 */ 0412 QRegion regionFromPolygon ( const GeoDataLinearRing & linearRing, 0413 Qt::FillRule fillRule, qreal strokeWidth = 3 ) const; 0414 0415 0416 /*! 0417 \brief Draws a given polygon (which may contain holes). 0418 0419 The outline of the \a polygon is drawn using the current pen. The 0420 background is painted using the current brush of the painter. 0421 Like in QPainter::drawPolygon() the \a fillRule specifies the 0422 fill algorithm that is used to fill the polygon. 0423 0424 \see GeoDataPolygon 0425 */ 0426 void drawPolygon ( const GeoDataPolygon & polygon, 0427 Qt::FillRule fillRule = Qt::OddEvenFill ); 0428 0429 0430 QVector<QPolygonF*> createFillPolygons( const QVector<QPolygonF*> & outerPolygons, 0431 const QVector<QPolygonF*> & innerPolygons ) const; 0432 0433 /*! 0434 \brief Draws a rectangle at the given position. 0435 The rectangle is placed with its center located at the given 0436 \a centerPosition. 0437 0438 For the outline it uses the painter's pen and for the background the 0439 painter's brush. 0440 0441 If \a isGeoProjected is true then the outline of the rectangle is drawn 0442 in geographic coordinates. In this case the \a width and the \a height 0443 are interpreted to be degrees. 0444 If \a isGeoProjected is false then the outline of the rectangle is drawn 0445 in screen coordinates. In this case the \a width and the \a height 0446 are interpreted to be pixels. 0447 0448 \see GeoDataCoordinates 0449 */ 0450 void drawRect ( const GeoDataCoordinates & centerPosition, 0451 qreal width, qreal height, 0452 bool isGeoProjected = false ); 0453 0454 0455 /*! 0456 \brief Creates a region for a rectangle at a given position. 0457 0458 A QRegion object is created that represents the area covered by 0459 GeoPainter::drawRect(). This can be used e.g. for input event handling 0460 for objects that have been painted using GeoPainter::drawRect(). 0461 0462 The isGeoProjected parameter is used the same way as for 0463 GeoPainter::drawRect(). 0464 0465 The \a strokeWidth allows to extrude the QRegion by half the amount of 0466 "stroke width" pixels. For input event handling it's always advisable to use 0467 a width that is slightly bigger than the width of the painter's pen. This is 0468 especially true for small objects. 0469 0470 \see GeoDataCoordinates 0471 */ 0472 QRegion regionFromRect ( const GeoDataCoordinates & centerPosition, 0473 qreal width, qreal height, 0474 bool isGeoProjected = false, 0475 qreal strokeWidth = 3 ) const; 0476 0477 0478 /*! 0479 \brief Draws a rectangle with rounded corners at the given position. 0480 The rectangle is placed with its center located at the given 0481 \a centerPosition. 0482 0483 For the outline it uses the painter's pen and for the background the 0484 painter's brush. 0485 Unlike in QPainter::drawRoundedRect() the rounded corners are not specified 0486 in percentage but in pixels to provide for optimal aesthetics. 0487 0488 \param centerPosition Position of rectangle center 0489 \param width Width of the rectangle in pixels 0490 \param height Height of the rectangle in pixels 0491 \param xRnd Specifies the geometry of the rounded corners in pixels along 0492 the x-axis. 0493 \param yRnd Specifies the geometry of the rounded corners in pixels along 0494 the y-axis. 0495 0496 \see GeoDataCoordinates 0497 */ 0498 void drawRoundedRect(const GeoDataCoordinates ¢erPosition, 0499 qreal width, qreal height, 0500 qreal xRnd = 25.0, qreal yRnd = 25.0); 0501 0502 0503 void drawTextFragment(const QPoint &position, const QString &text, 0504 const qreal fontSize, const QColor &color = Qt::black, 0505 const Frames &flags = Frames()); 0506 0507 0508 // Reenabling QPainter+ClipPainter methods. 0509 using QPainter::drawText; 0510 using QPainter::drawEllipse; 0511 using QPainter::drawImage; 0512 using QPainter::drawPixmap; 0513 using QPainter::drawPoint; 0514 using ClipPainter::drawPolyline; 0515 using ClipPainter::drawPolygon; 0516 using QPainter::drawRect; 0517 using QPainter::drawRoundedRect; 0518 0519 private: 0520 Q_DISABLE_COPY( GeoPainter ) 0521 GeoPainterPrivate * const d; 0522 }; 0523 0524 } 0525 0526 #endif