/* * Copyright 2012, 2013 Thomas Schöps * Copyright 2014-2019 Kai Pastor * * This file is part of OpenOrienteering. * * OpenOrienteering is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenOrienteering is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenOrienteering. If not, see . */ #ifndef OPENORIENTEERING_MAP_VIEW_H #define OPENORIENTEERING_MAP_VIEW_H #include #include #include #include #include #include #include #include #include "map_coord.h" class QLatin1String; class QRectF; class QXmlStreamReader; class QXmlStreamWriter; namespace OpenOrienteering { class Map; class Template; /** * Contains the visibility information for a template (or the map). */ class TemplateVisibility { public: /** Opacity from 0.0 (invisible) to 1.0 (opaque) */ qreal opacity; /** Visibility flag */ bool visible; /** Returns true when the template is visible but not opaque. */ bool hasAlpha() const; }; bool operator==(TemplateVisibility lhs, TemplateVisibility rhs); bool operator!=(TemplateVisibility lhs, TemplateVisibility rhs); /** * Stores view position, zoom, rotation and grid / template visibilities * to define a view onto a map. * * These parameters define the view coordinates with origin at the view's center, * measured in pixels. The class provides methods to convert between view * coordinates and map coordinates (defined as millimeter on map paper). */ class MapView : public QObject { Q_OBJECT Q_FLAGS(ChangeFlags VisibilityFeature) public: enum ChangeFlag { NoChange = 0, CenterChange = 1, ZoomChange = 2, RotationChange = 4, }; Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag) enum VisibilityFeature { MultipleFeatures = 0, GridVisible = 1, OverprintingEnabled = 2, AllTemplatesHidden = 4, TemplateVisible = 8, MapVisible = 16, }; /** * Creates a default view looking at the origin. * * The parameter map must not be null. */ MapView(QObject* parent, Map* map); /** Creates a default view looking at the origin. * * The map takes ownership of the map view. It must not be null. */ MapView(Map* map); /** Destroys the map view. */ ~MapView() override; /** * Saves the map view state to an XML stream. * @param xml The XML output stream. * @param element_name The name of the element which will be written. * @param template_details Save template visibilities (default: true) */ void save(QXmlStreamWriter& xml, const QLatin1String& element_name, bool template_details = true) const; /** Loads the map view state from the current element of an xml stream. */ void load(QXmlStreamReader& xml); /** * Redraws all map widgets completely. * * Note that this calls QWidget::update() which does not cause an immediate * repaint; instead it schedules a paint event. * * Completely repainting widgets can be slow. * Try to do partial updates instead, if possible. */ void updateAllMapWidgets(); /** Converts the point (with origin at the center of the view) to map coordinates */ MapCoord viewToMap(const QPointF& point) const; /** Converts the point (with origin at the center of the view) to map coordinates */ MapCoordF viewToMapF(const QPointF& point) const; /// Converts map coordinates to view coordinates (with origin at the center of the view) QPointF mapToView(const MapCoord& coords) const; /// Converts map coordinates to view coordinates (with origin at the center of the view) QPointF mapToView(const QPointF& coords) const; /** * Converts a length from native map coordinates to the current length in view pixels. */ qreal lengthToPixel(qreal length) const; /** * Converts a length from current view pixels to native map coordinates. */ qreal pixelToLength(qreal pixel) const; /** * Calculates the bounding box of the map coordinates which can be viewed * using the given view coordinates rect */ QRectF calculateViewedRect(QRectF view_rect) const; /** * Calculates the bounding box in view coordinates * of the given map coordinates rect */ QRectF calculateViewBoundingBox(QRectF map_rect) const; /** * Returns a QTransform suitable for QPainter, so objects defined in * map coordinates will be drawn at their view coordinates. Append a * viewport transformation to this to get a complete map-to-viewport transformation * which makes the view center appear at the viewport center. * * Note: The transform is to be combined with the painter's existing transform. */ const QTransform& worldTransform() const; // Panning /** Returns the current pan offset (when dragging the map). */ QPoint panOffset() const; /** Sets the current pan offset while the map is being dragged. */ void setPanOffset(const QPoint& offset); /** * Finishes panning the map. * * @param offset The final offset, relative to the start of the operation. */ void finishPanning(const QPoint& offset); /** Returns the map this view is defined on. */ const Map* getMap() const; /** Returns the map this view is defined on. */ Map* getMap(); /** * Zooms the maps (in steps), preserving the given cursor position. * * @param num_steps Number of zoom steps to zoom in. Negative numbers zoom out. * @param cursor_pos_view The cursor position in view coordinates, must be * set if preserve_cursor_pos is used. */ void zoomSteps(double num_steps, const QPointF& cursor_pos_view); /** * Zooms the maps (in steps), preserving the center of the view. * * @param num_steps Number of zoom steps to zoom in. Negative numbers zoom out. */ void zoomSteps(double num_steps); /** * Returns the final zoom factor for use in transformations. * Depends on the pixel per millimeter of the display. */ double calculateFinalZoomFactor() const; /** Returns the raw zoom factor, see also calculateFinalZoomFactor(). */ double getZoom() const; /** Sets the zoom factor relative to the given point.*/ void setZoom(double value, const QPointF& center); /** Sets the zoom factor. */ void setZoom(double value); /** Returns the view rotation (in radians). */ double getRotation() const; /** Sets the view rotation (in radians). */ void setRotation(double value); /** Returns the position of the view center. */ MapCoord center() const; /** Sets the position of the view center. */ void setCenter(const MapCoord& pos); // Map and template visibilities /** Returns the effectiv visibility settings of the map drawing. * * Other than getMapVisibility, this will always return an (100 %) opaque, * visible configuration when areAllTemplatesHidden() is true, * and it return an invisible configuration when the map's opacity is * below 0.005. */ TemplateVisibility effectiveMapVisibility() const; /** Returns the visibility settings of the map drawing. */ TemplateVisibility getMapVisibility() const; void setMapVisibility(TemplateVisibility vis); /** * Checks if the template is visible without creating * a template visibility object if none exists */ bool isTemplateVisible(const Template* temp) const; /** * Returns the template visibility. * * If the template is unknown, returns default settings. */ TemplateVisibility getTemplateVisibility(const Template* temp) const; /** * Sets the template visibility, and emits a change signal. */ void setTemplateVisibility(Template* temp, TemplateVisibility vis); /** Enables or disables hiding all templates in this view */ void setAllTemplatesHidden(bool value); /** * Returns if the "hide all templates" toggle is active. * See also setHideAllTemplates(). */ bool areAllTemplatesHidden() const; /** Returns if the map grid is visible. */ bool isGridVisible() const; /** Sets the map grid visibility. */ void setGridVisible(bool visible); /** Returns if overprinting simulation is enabled. */ bool isOverprintingSimulationEnabled() const; /** Enables or disables overprinting simulation. */ void setOverprintingSimulationEnabled(bool enabled); /** * Returns true if any of the visible elements is not opaque. */ bool hasAlpha() const; /** Temporarily blocks automatic template loading on visibility changes. */ void setTemplateLoadingBlocked(bool blocked); /** Returns true when template loading on visibility changes is disabled. */ bool templateLoadingBlocked() const { return template_loading_blocked; } signals: /** * Indicates a change of the viewed area of the map. * * @param change The aspects that have changed. */ void viewChanged(OpenOrienteering::MapView::ChangeFlags change); /** * Indicates a change of the pan offset. */ void panOffsetChanged(const QPoint& offset); /** * Indicates a particular change of visibility. * * @param feature The map view feature that has changed. * @param active The features current state of activation. * @param temp If a the feature is a template, a pointer to this template. */ void visibilityChanged(OpenOrienteering::MapView::VisibilityFeature feature, bool active, const OpenOrienteering::Template* temp = nullptr); public: // Static /** The global zoom in limit for the zoom factor. */ static const double zoom_in_limit; /** The global zoom out limit for the zoom factor. */ static const double zoom_out_limit; protected: /** * Sets the template visibility without emitting signals. */ bool setTemplateVisibilityHelper(const Template *temp, TemplateVisibility vis); /** * Creates the visibility data when a template is added to the map. */ void onTemplateAdded(int pos, Template* temp); /** * Removes the visibility data when a template is deleted. */ void onTemplateDeleted(int pos, const Template* temp); private: Q_DISABLE_COPY(MapView) struct TemplateVisibilityEntry : public TemplateVisibility { const Template* temp; TemplateVisibilityEntry() = default; TemplateVisibilityEntry(const TemplateVisibilityEntry&) = default; TemplateVisibilityEntry(TemplateVisibilityEntry&&) = default; TemplateVisibilityEntry& operator=(const TemplateVisibilityEntry&) = default; TemplateVisibilityEntry& operator=(TemplateVisibilityEntry&&) = default; TemplateVisibilityEntry(const Template* temp, TemplateVisibility vis) : TemplateVisibility(vis) , temp(temp) {} }; typedef std::vector TemplateVisibilityVector; void updateTransform(); // recalculates the x_to_y matrices TemplateVisibilityVector::const_iterator findVisibility(const Template* temp) const; TemplateVisibilityVector::iterator findVisibility(const Template* temp); Map* map; double zoom; // factor double rotation; // counterclockwise 0 to 2*PI. This is the viewer rotation, so the map is rotated clockwise MapCoord center_pos;// position of the viewer, positive values move the map to the left; the position is in 1/1000 mm QPoint pan_offset; // the distance the content of the view was dragged with the mouse, in pixels QTransform view_to_map; QTransform map_to_view; TemplateVisibility map_visibility; TemplateVisibilityVector template_visibilities; bool all_templates_hidden; bool grid_visible; bool overprinting_simulation_enabled; bool template_loading_blocked; }; // ### TemplateVisibility inline code ### inline bool operator==(TemplateVisibility lhs, TemplateVisibility rhs) { return lhs.visible == rhs.visible && qFuzzyCompare(1.0+rhs.opacity, 1.0+lhs.opacity); } inline bool operator!=(TemplateVisibility lhs, TemplateVisibility rhs) { return !(lhs == rhs); } // ### MapView inline code ### inline MapCoord MapView::viewToMap(const QPointF& point) const { return MapCoord(view_to_map.map(point)); } inline MapCoordF MapView::viewToMapF(const QPointF& point) const { return MapCoordF(view_to_map.map(point)); } inline const QTransform& MapView::worldTransform() const { return map_to_view; } inline Map* MapView::getMap() { return map; } inline const Map* MapView::getMap() const { return map; } inline double MapView::calculateFinalZoomFactor() const { return lengthToPixel(1000.0); } inline double MapView::getZoom() const { return zoom; } inline double MapView::getRotation() const { return rotation; } inline MapCoord MapView::center() const { return center_pos; } inline QPoint MapView::panOffset() const { return pan_offset; } inline TemplateVisibility MapView::getMapVisibility() const { return map_visibility; } inline bool MapView::areAllTemplatesHidden() const { return all_templates_hidden; } inline bool MapView::isGridVisible() const { return grid_visible; } inline bool MapView::isOverprintingSimulationEnabled() const { return overprinting_simulation_enabled; } } // namespace OpenOrienteering Q_DECLARE_OPERATORS_FOR_FLAGS(OpenOrienteering::MapView::ChangeFlags) #endif