1 /* 2 * Copyright 2012, 2013 Thomas Schöps 3 * Copyright 2012-2020 Kai Pastor 4 * 5 * This file is part of OpenOrienteering. 6 * 7 * OpenOrienteering is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * OpenOrienteering is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with OpenOrienteering. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 22 #ifndef OPENORIENTEERING_TEMPLATE_IMAGE_H 23 #define OPENORIENTEERING_TEMPLATE_IMAGE_H 24 25 #include <memory> 26 #include <vector> 27 28 #include <QtGlobal> 29 #include <QByteArray> 30 #include <QColor> 31 #include <QImage> 32 #include <QObject> 33 #include <QPointF> 34 #include <QRectF> 35 #include <QRgb> 36 #include <QString> 37 #include <QTransform> 38 39 #include "templates/template.h" 40 41 class QPainter; 42 class QPointF; 43 class QRectF; 44 class QWidget; 45 class QXmlStreamReader; 46 class QXmlStreamWriter; 47 48 namespace OpenOrienteering { 49 50 class Georeferencing; 51 class Map; 52 class MapCoordF; 53 54 55 /** 56 * Template showing a raster image. 57 * Can be georeferenced or non-georeferenced. 58 */ 59 class TemplateImage : public Template 60 { 61 Q_OBJECT 62 public: 63 /** 64 * Information fragment about template image georeferencing. 65 * 66 * A GeoreferencingOption may carry information about the CRS and/or the 67 * pixel-to-world transform for a template image. The crs_spec is empty 68 * if the CRS is unknown. The transform's source is empty if the 69 * pixel-to-world transformation is unknown. 70 */ 71 struct GeoreferencingOption 72 { 73 struct Transform 74 { 75 QTransform pixel_to_world = {}; ///< The transformation from pixel space to CRS space. 76 QByteArray source = {}; ///< The source of the pixel-to-world transform. 77 }; 78 79 QString crs_spec = {}; ///< The specification of the CRS uses for georeferencing. 80 Transform transform = {}; ///< The transformation from pixel space to CRS space. 81 }; 82 83 /** 84 * A collection of alternative and/or complementary georeferencing information fragments. 85 */ 86 struct GeoreferencingOptions 87 { 88 GeoreferencingOption effective; ///< The effective option, if CRS and transform are defined. 89 GeoreferencingOption world_file; ///< A pixel-to-world transform from a world file. 90 GeoreferencingOption template_file; ///< CRS and/or pixel-to-world transform from the template file. 91 }; 92 93 /** 94 * Returns the filename extensions supported by this template class. 95 */ 96 static const std::vector<QByteArray>& supportedExtensions(); 97 98 TemplateImage(const QString& path, Map* map); 99 protected: 100 TemplateImage(const TemplateImage& proto); 101 public: 102 ~TemplateImage() override; 103 104 TemplateImage* duplicate() const override; 105 getTemplateType()106 const char* getTemplateType() const override {return "TemplateImage";} isRasterGraphics()107 bool isRasterGraphics() const override {return true;} 108 109 bool saveTemplateFile() const override; 110 void saveTypeSpecificTemplateConfiguration(QXmlStreamWriter& xml) const override; 111 bool loadTypeSpecificTemplateConfiguration(QXmlStreamReader& xml) override; 112 113 bool loadTemplateFileImpl(bool configuring) override; 114 bool postLoadConfiguration(QWidget* dialog_parent, bool& out_center_in_view) override; 115 void unloadTemplateFileImpl() override; 116 117 void drawTemplate(QPainter* painter, const QRectF& clip_rect, double scale, bool on_screen, qreal opacity) const override; 118 QRectF getTemplateExtent() const override; canBeDrawnOnto()119 bool canBeDrawnOnto() const override { return drawable; } 120 121 /** 122 * Calculates the image's center of gravity in template coordinates by 123 * iterating over all pixels, leaving out the pixels with background_color. 124 */ 125 QPointF calcCenterOfGravity(QRgb background_color); 126 127 /** Returns the internal QImage. */ getImage()128 inline const QImage& getImage() const {return image;} 129 130 /** 131 * Returns which georeferencing methods are known to be available. 132 * 133 * (This does not imply that the image is in georeferenced mode.) 134 * 135 * Invariant: The list is never empty. It always contains at least an entry 136 * of type Georeferencing_None. This entry is always the last one. 137 */ availableGeoreferencing()138 const GeoreferencingOptions& availableGeoreferencing() const { return available_georef; } 139 140 bool canChangeTemplateGeoreferenced() override; 141 bool trySetTemplateGeoreferenced(bool value, QWidget* dialog_parent) override; 142 143 144 public slots: 145 void updateGeoreferencing(); 146 147 protected: 148 /** 149 * Collects available georeferencing information. 150 * 151 * This function is meant to be used from loadTemplateFileImpl() to set the 152 * available_georef member. The parameter template_file_option is used to 153 * efficiently provide georeferencing information from the template file 154 * itself. 155 */ 156 GeoreferencingOptions findAvailableGeoreferencing(GeoreferencingOption template_file_option) const; 157 158 /** 159 * Tests if the available georeferencing options can be used with the current map. 160 * 161 * To be usable, the effective option must provide a transformation, and 162 * if the map's CRS spec is not empty (local georeferencing), the effective 163 * option's CRS spec must not be empty. 164 * 165 * Note that changing the state to georeferenced may still fail for invalid 166 * CRS specs. 167 */ 168 bool isGeoreferencingUsable() const; 169 170 /** Information about an undo step for the paint-on-template functionality. */ 171 struct DrawOnImageUndoStep 172 { 173 /** Copy of previous image part */ 174 QImage image; 175 176 /** X position of image part origin */ 177 int x; 178 179 /** Y position of image part origin */ 180 int y; 181 }; 182 183 void drawOntoTemplateImpl(MapCoordF* coords, int num_coords, const QColor& color, qreal width) override; 184 void drawOntoTemplateUndo(bool redo) override; 185 void addUndoStep(const DrawOnImageUndoStep& new_step); 186 void calculateGeoreferencing(); 187 void updatePosFromGeoreferencing(); 188 189 QImage image; 190 191 std::vector< DrawOnImageUndoStep > undo_steps; 192 /// Current index in undo_steps, where 0 means before the first item. 193 int undo_index = 0; 194 /// A flag indicating that this template can be drawn onto. 195 bool drawable = false; 196 197 GeoreferencingOptions available_georef; 198 std::unique_ptr<Georeferencing> georef; 199 }; 200 201 202 } // namespace OpenOrienteering 203 204 #endif 205