File indexing completed on 2024-04-21 03:49:36

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 "marble_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 MARBLE_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 &centerCoordinates,
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 &centerPosition,
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