File indexing completed on 2025-02-16 04:21:49
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KOSMINDOORMAP_VIEW_H 0008 #define KOSMINDOORMAP_VIEW_H 0009 0010 #include "kosmindoormap_export.h" 0011 0012 #include <KOSM/Datatypes> 0013 0014 #include <QDateTime> 0015 #include <QObject> 0016 #include <QRectF> 0017 #include <QSize> 0018 #include <QTransform> 0019 0020 namespace KOSMIndoorMap { 0021 0022 /** View transformations and transformation manipulation. 0023 * There are three different coordinate systems involved here: 0024 * - The geographic world coordinates of the OSM input data. 0025 * This uses OSM::Coordinate. 0026 * - The scene coordinates which have a the Web Mercator projection applied (see https://en.wikipedia.org/wiki/Mercator_projection). 0027 * This uses QPointF ranging from 0x0 to 256x256 0028 * - The screen coordinates (ie. visible pixels on screen). 0029 * This uses QPoint. 0030 * Further, there's also three slight variations of those in use here: 0031 * - "HUD" coordinates: elements that follow the scene coordinates for their positioning, 0032 * but the screen coordinates regarding scaling and rotation. This is used for map labels. 0033 * - Geographic distances. This is needed to display things in a fixed width in meters in the scene, 0034 * or to compute the map scale. Note that this only works due to the relatively high zoom levels, 0035 * so that earth curvature or map projection effects are negligible. 0036 * - "pan space": same transform as screen space, but with the origin at the origin of the scene bounding box 0037 * This is useful for implementing scene-wide panning and showing scroll bars. 0038 */ 0039 class KOSMINDOORMAP_EXPORT View : public QObject 0040 { 0041 Q_OBJECT 0042 Q_PROPERTY(double panX READ panX NOTIFY transformationChanged) 0043 Q_PROPERTY(double panY READ panY NOTIFY transformationChanged) 0044 Q_PROPERTY(double panWidth READ panWidth NOTIFY transformationChanged) 0045 Q_PROPERTY(double panHeight READ panHeight NOTIFY transformationChanged) 0046 Q_PROPERTY(int floorLevel READ level WRITE setLevel NOTIFY floorLevelChanged) 0047 Q_PROPERTY(QRectF viewport READ viewport NOTIFY transformationChanged) 0048 Q_PROPERTY(double zoomLevel READ zoomLevel NOTIFY transformationChanged) 0049 Q_PROPERTY(QDateTime beginTime READ beginTime WRITE setBeginTime NOTIFY timeChanged) 0050 Q_PROPERTY(QDateTime endTime READ endTime WRITE setEndTime NOTIFY timeChanged) 0051 public: 0052 explicit View(QObject *parent = nullptr); 0053 ~View(); 0054 0055 /** Map a geographic coordinate to a scene coordinate, ie. apply the mercator projection. */ 0056 [[nodiscard]] static QPointF mapGeoToScene(OSM::Coordinate coord); 0057 [[nodiscard]] static QRectF mapGeoToScene(OSM::BoundingBox box); 0058 /** Map a scene coordinate to a geographic one, ie. apply the inverse mercator projection. */ 0059 [[nodiscard]] static OSM::Coordinate mapSceneToGeo(QPointF p); 0060 Q_INVOKABLE [[nodiscard]] static OSM::BoundingBox mapSceneToGeo(const QRectF &box); 0061 0062 /** Screen-space sizes, ie the size of the on-screen area used for displaying. */ 0063 int screenWidth() const; 0064 int screenHeight() const; 0065 void setScreenSize(QSize size); 0066 0067 /** The transformation to apply to scene coordinate to get to the view on screen. */ 0068 QTransform sceneToScreenTransform() const; 0069 0070 /** The (floor) level to display. 0071 * @see MapLevel. 0072 */ 0073 int level() const; 0074 void setLevel(int level); 0075 0076 /** OSM-compatible zoom level, ie. the 2^level-th subdivision of the scene space. */ 0077 double zoomLevel() const; 0078 /** Set the zoom level to @p zoom, and adjusting it around center position @p center. */ 0079 Q_INVOKABLE void setZoomLevel(double zoom, QPointF screenCenter); 0080 0081 /** The sub-rect of the scene bounding box currently displayed. 0082 * Specified in scene coordinates. 0083 */ 0084 [[nodiscard]] QRectF viewport() const; 0085 void setViewport(const QRectF &viewport); 0086 0087 /** Computes the viewport for the given @p zoom level and @p screenCenter. 0088 * This does not apply the zoom change to the view itself though. 0089 */ 0090 [[nodiscard]] QRectF viewportForZoom(double zoom, QPointF screenCenter) const; 0091 0092 /** The bounding box of the scene. 0093 * The viewport cannot exceed this area. 0094 */ 0095 QRectF sceneBoundingBox() const; 0096 void setSceneBoundingBox(OSM::BoundingBox bbox); 0097 void setSceneBoundingBox(const QRectF &bbox); 0098 0099 /** Converts a point in scene coordinates to screen coordinates. */ 0100 QPointF mapSceneToScreen(QPointF scenePos) const; 0101 /** Converts a rectangle in scene coordinates to screen coordinates. */ 0102 QRectF mapSceneToScreen(const QRectF &sceneRect) const; 0103 /** Converts a point in screen coordinates to scene coordinates. */ 0104 QPointF mapScreenToScene(QPointF screenPos) const; 0105 /** Converts a distance in screen coordinates to a distance in scene coordinates. */ 0106 double mapScreenDistanceToSceneDistance(double distance) const; 0107 0108 /** Returns how many units in scene coordinate represent the distance of @p meters in the current view transformation. */ 0109 double mapMetersToScene(double meters) const; 0110 /** Returns how many pixels on screen represent the distance of @p meters with the current view transformation. */ 0111 Q_INVOKABLE double mapMetersToScreen(double meters) const; 0112 /** Returns how many meters are represented by @p pixels with the current view transformation. */ 0113 Q_INVOKABLE double mapScreenToMeters(int pixels) const; 0114 0115 void panScreenSpace(QPoint offset); 0116 /** Increase zoom level by one/scale up by 2x around the screen position @p center. */ 0117 Q_INVOKABLE void zoomIn(QPointF screenCenter); 0118 /** Decrease zoom level by one/scale down by 2x around the screen position @p center. */ 0119 Q_INVOKABLE void zoomOut(QPointF screenCenter); 0120 0121 /** Position of the viewport in pan coordinates. */ 0122 double panX() const; 0123 double panY() const; 0124 /** Size of the pan-able area in screen coordinates. */ 0125 double panWidth() const; 0126 double panHeight() const; 0127 0128 /** Move the viewport to the pan coordinates @p x and @p y. */ 0129 Q_INVOKABLE void panTopLeft(double x, double y); 0130 0131 /** Device tranformation for manual high DPI scaling. */ 0132 QTransform deviceTransform() const; 0133 void setDeviceTransform(const QTransform &t); 0134 0135 /** Center the view on the given geo-coordinate. */ 0136 Q_INVOKABLE void centerOnGeoCoordinate(QPointF geoCoord); 0137 0138 /** Time range that is displayed. 0139 * This matters for example when opening hours are considered for styling. 0140 */ 0141 QDateTime beginTime() const; 0142 void setBeginTime(const QDateTime &beginTime); 0143 QDateTime endTime() const; 0144 void setEndTime(const QDateTime &endTime); 0145 0146 Q_SIGNALS: 0147 void transformationChanged(); 0148 void floorLevelChanged(); 0149 void timeChanged(); 0150 0151 private: 0152 /** Ensure we stay within the bounding box with the viewport, call after viewport modification. */ 0153 void constrainViewToScene(); 0154 [[nodiscard]] QRectF constrainedViewport(QRectF viewport) const; 0155 0156 /** Needs to be called for any update to the viewport to updates internal caches 0157 * and emits change signals. 0158 */ 0159 void updateViewport(); 0160 0161 QRectF m_bbox; 0162 QRectF m_viewport; 0163 QSize m_screenSize; 0164 QTransform m_deviceTransform = {}; 0165 int m_level = 0; 0166 0167 // cached values 0168 double m_screenWidthInMeters = 1.0; 0169 QTransform m_sceneToScreenTransform; 0170 QTransform m_screenToSceneTransform; 0171 0172 QDateTime m_beginTime; 0173 QDateTime m_endTime; 0174 }; 0175 0176 } 0177 0178 #endif // KOSMINDOORMAP_VIEW_H