1 /*
2 * Copyright 2014 Thomas Schöps
3 * Copyright 2014, 2015 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 #include "draw_point_gps_tool.h"
23
24 #include <Qt>
25 #include <QtGlobal>
26 #include <QCursor>
27 #include <QKeyEvent>
28 #include <QLabel>
29 #include <QPainter>
30 #include <QPixmap>
31 #include <QPoint>
32 #include <QString>
33
34 #include "core/map.h"
35 #include "core/map_coord.h"
36 #include "core/map_view.h"
37 #include "core/objects/object.h"
38 #include "core/renderables/renderable.h"
39 #include "core/symbols/point_symbol.h"
40 #include "core/symbols/symbol.h"
41 #include "gui/map/map_editor.h"
42 #include "gui/map/map_widget.h"
43 #include "sensors/gps_display.h"
44 #include "tools/tool.h"
45 #include "undo/object_undo.h"
46 #include "util/util.h"
47
48
49 namespace OpenOrienteering {
50
DrawPointGPSTool(GPSDisplay * gps_display,MapEditorController * editor,QAction * tool_action)51 DrawPointGPSTool::DrawPointGPSTool(GPSDisplay* gps_display, MapEditorController* editor, QAction* tool_action)
52 : MapEditorToolBase(QCursor(QPixmap(QString::fromLatin1(":/images/cursor-draw-point.png")), 11, 11), DrawPoint, editor, tool_action)
53 , renderables(new MapRenderables(map()))
54 {
55 useTouchCursor(false);
56
57 preview_object = nullptr;
58 if (gps_display->hasValidPosition())
59 newGPSPosition(gps_display->getLatestGPSCoord(), gps_display->getLatestGPSCoordAccuracy());
60
61 connect(gps_display, &GPSDisplay::mapPositionUpdated, this, &DrawPointGPSTool::newGPSPosition);
62 connect(editor, &MapEditorController::activeSymbolChanged, this, &DrawPointGPSTool::activeSymbolChanged);
63 connect(map(), &Map::symbolDeleted, this, &DrawPointGPSTool::symbolDeleted);
64 }
65
~DrawPointGPSTool()66 DrawPointGPSTool::~DrawPointGPSTool()
67 {
68 if (preview_object)
69 {
70 renderables->removeRenderablesOfObject(preview_object, false);
71 delete preview_object;
72 }
73 if (help_label)
74 editor->deletePopupWidget(help_label);
75 }
76
initImpl()77 void DrawPointGPSTool::initImpl()
78 {
79 if (editor->isInMobileMode())
80 {
81 help_label = new QLabel(tr("Touch the map to finish averaging"));
82 editor->showPopupWidget(help_label, QString{});
83 }
84 }
85
newGPSPosition(const MapCoordF & coord,float accuracy)86 void DrawPointGPSTool::newGPSPosition(const MapCoordF& coord, float accuracy)
87 {
88 auto point = reinterpret_cast<PointSymbol*>(editor->activeSymbol());
89
90 // Calculate weight from accuracy. This is arbitrarily chosen.
91 float weight;
92 if (accuracy < 0)
93 weight = 1; // accuracy unknown
94 else
95 weight = 1.0f / qMax(0.5f, accuracy);
96
97 if (! preview_object)
98 {
99 // This is the first received position.
100 preview_object = new PointObject(point);
101
102 x_sum = weight * coord.x();
103 y_sum = weight * coord.y();
104 weights_sum = weight;
105 }
106 else
107 {
108 renderables->removeRenderablesOfObject(preview_object, false);
109 if (preview_object->getSymbol() != point)
110 {
111 bool success = preview_object->setSymbol(point, true);
112 Q_ASSERT(success);
113 Q_UNUSED(success);
114 }
115
116 x_sum += weight * coord.x();
117 y_sum += weight * coord.y();
118 weights_sum += weight;
119 }
120
121 MapCoordF avg_position(x_sum / weights_sum, y_sum / weights_sum);
122 preview_object->setPosition(avg_position);
123 preview_object->setRotation(0);
124 preview_object->update();
125 renderables->insertRenderablesOfObject(preview_object);
126 updateDirtyRect();
127 }
128
clickRelease()129 void DrawPointGPSTool::clickRelease()
130 {
131 if (! preview_object)
132 return;
133
134 auto point = preview_object->duplicate()->asPoint();
135
136 int index = map()->addObject(point);
137 map()->clearObjectSelection(false);
138 map()->addObjectToSelection(point, true);
139 map()->setObjectsDirty();
140 map()->clearDrawingBoundingBox();
141 renderables->removeRenderablesOfObject(preview_object, false);
142
143 auto undo_step = new DeleteObjectsUndoStep(map());
144 undo_step->addObject(index);
145 map()->push(undo_step);
146
147 setEditingInProgress(false);
148 deactivate();
149 }
150
keyPress(QKeyEvent * event)151 bool DrawPointGPSTool::keyPress(QKeyEvent* event)
152 {
153 switch (event->key())
154 {
155 case Qt::Key_Tab:
156 deactivate();
157 return true;
158
159 }
160 return false;
161 }
162
drawImpl(QPainter * painter,MapWidget * widget)163 void DrawPointGPSTool::drawImpl(QPainter* painter, MapWidget* widget)
164 {
165 if (preview_object)
166 {
167 const MapView* map_view = widget->getMapView();
168 painter->save();
169 painter->translate(widget->width() / 2.0 + map_view->panOffset().x(),
170 widget->height() / 2.0 + map_view->panOffset().y());
171 painter->setWorldTransform(map_view->worldTransform(), true);
172
173 RenderConfig config = { *map(), map_view->calculateViewedRect(widget->viewportToView(widget->rect())), map_view->calculateFinalZoomFactor(), RenderConfig::Tool, 0.5 };
174 renderables->draw(painter, config);
175
176 painter->restore();
177 }
178 }
179
updateDirtyRectImpl(QRectF & rect)180 int DrawPointGPSTool::updateDirtyRectImpl(QRectF& rect)
181 {
182 if (preview_object)
183 {
184 rectIncludeSafe(rect, preview_object->getExtent());
185 return 0;
186 }
187 else
188 return -1;
189 }
190
updateStatusText()191 void DrawPointGPSTool::updateStatusText()
192 {
193 setStatusBarText( tr("<b>Click</b>: Finish setting the object. "));
194 }
195
objectSelectionChangedImpl()196 void DrawPointGPSTool::objectSelectionChangedImpl()
197 {
198 // NOP
199 }
200
activeSymbolChanged(const Symbol * symbol)201 void DrawPointGPSTool::activeSymbolChanged(const Symbol* symbol)
202 {
203 if (!symbol || symbol->getType() != Symbol::Point || symbol->isHidden())
204 {
205 if (symbol && symbol->isHidden())
206 deactivate();
207 else
208 switchToDefaultDrawTool(symbol);
209 }
210 else
211 last_used_symbol = symbol;
212 }
213
symbolDeleted(int pos,const Symbol * old_symbol)214 void DrawPointGPSTool::symbolDeleted(int pos, const Symbol* old_symbol)
215 {
216 Q_UNUSED(pos);
217
218 if (last_used_symbol == old_symbol)
219 deactivate();
220 }
221
222
223 } // namespace OpenOrienteering
224