1 #include <cmath>
2 #include <QLocale>
3 #include "data/data.h"
4 #include "tooltip.h"
5 #include "elevationgraphitem.h"
6 #include "elevationgraph.h"
7 
8 
nMin(qreal a,qreal b)9 static qreal nMin(qreal a, qreal b)
10 {
11 	if (std::isnan(a))
12 		return std::isnan(b) ? NAN : b;
13 	else
14 		return std::isnan(b) ? a : qMin(a, b);
15 }
16 
nMax(qreal a,qreal b)17 static qreal nMax(qreal a, qreal b)
18 {
19 	if (std::isnan(a))
20 		return std::isnan(b) ? NAN : b;
21 	else
22 		return std::isnan(b) ? a : qMax(a, b);
23 }
24 
ElevationGraph(QWidget * parent)25 ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent)
26 {
27 	_trackAscent = 0;
28 	_routeAscent = 0;
29 	_trackDescent = 0;
30 	_routeDescent = 0;
31 	_trackMin = NAN;
32 	_trackMax = NAN;
33 	_routeMin = NAN;
34 	_routeMax = NAN;
35 
36 	_showRoutes = true;
37 	_showTracks = true;
38 
39 	setYUnits(Metric);
40 	setYLabel(tr("Elevation"));
41 	setMinYRange(50.0);
42 }
43 
~ElevationGraph()44 ElevationGraph::~ElevationGraph()
45 {
46 	qDeleteAll(_tracks);
47 	qDeleteAll(_routes);
48 }
49 
setInfo()50 void ElevationGraph::setInfo()
51 {
52 	if (std::isnan(max()) || std::isnan(min()))
53 		clearInfo();
54 	else {
55 		QLocale l(QLocale::system());
56 
57 		GraphView::addInfo(tr("Ascent"), l.toString(ascent() * yScale(),
58 		  'f', 0) + UNIT_SPACE + yUnits());
59 		GraphView::addInfo(tr("Descent"), l.toString(descent() * yScale(),
60 		  'f', 0) + UNIT_SPACE + yUnits());
61 		GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
62 		  0) + UNIT_SPACE + yUnits());
63 		GraphView::addInfo(tr("Minimum"), l.toString(min() * yScale(), 'f',
64 		  0) + UNIT_SPACE + yUnits());
65 	}
66 }
67 
loadGraph(const Graph & graph,PathType type,const QColor & color,bool primary)68 GraphItem *ElevationGraph::loadGraph(const Graph &graph, PathType type,
69   const QColor &color, bool primary)
70 {
71 	if (!graph.isValid())
72 		return 0;
73 
74 	ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
75 	  color, primary ? Qt::SolidLine : Qt::DashLine);
76 	gi->setUnits(_units);
77 
78 	if (type == TrackPath) {
79 		_tracks.append(gi);
80 		if (_showTracks)
81 			addGraph(gi);
82 
83 		if (primary) {
84 			_trackAscent += gi->ascent();
85 			_trackDescent += gi->descent();
86 			_trackMax = nMax(_trackMax, gi->max());
87 			_trackMin = nMin(_trackMin, gi->min());
88 		}
89 	} else {
90 		_routes.append(gi);
91 		if (_showRoutes)
92 			addGraph(gi);
93 
94 		if (primary) {
95 			_routeAscent += gi->ascent();
96 			_routeDescent += gi->descent();
97 			_routeMax = nMax(_routeMax, gi->max());
98 			_routeMin = nMin(_routeMin, gi->min());
99 		}
100 	}
101 
102 	return gi;
103 }
104 
loadData(const Data & data)105 QList<GraphItem*> ElevationGraph::loadData(const Data &data)
106 {
107 	QList<GraphItem*> graphs;
108 	GraphItem *primary, *secondary;
109 
110 	for (int i = 0; i < data.tracks().count(); i++) {
111 		QColor color(_palette.nextColor());
112 		const GraphPair &gp = data.tracks().at(i).elevation();
113 
114 		primary = loadGraph(gp.primary(), TrackPath, color, true);
115 		secondary = primary
116 		  ? loadGraph(gp.secondary(), TrackPath, color, false) : 0;
117 		if (primary && secondary)
118 			primary->setSecondaryGraph(secondary);
119 
120 		graphs.append(primary);
121 	}
122 	for (int i = 0; i < data.routes().count(); i++) {
123 		QColor color(_palette.nextColor());
124 		const GraphPair &gp = data.routes().at(i).elevation();
125 
126 		primary = loadGraph(gp.primary(), RoutePath, color, true);
127 		secondary = primary
128 		  ? loadGraph(gp.secondary(), RoutePath, color, false) : 0;
129 		if (primary && secondary)
130 			primary->setSecondaryGraph(secondary);
131 
132 		graphs.append(primary);
133 	}
134 	for (int i = 0; i < data.areas().count(); i++)
135 		_palette.nextColor();
136 
137 	setInfo();
138 	redraw();
139 
140 	return graphs;
141 }
142 
clear()143 void ElevationGraph::clear()
144 {
145 	qDeleteAll(_tracks);
146 	_tracks.clear();
147 	qDeleteAll(_routes);
148 	_routes.clear();
149 
150 	_trackAscent = 0;
151 	_routeAscent = 0;
152 	_trackDescent = 0;
153 	_routeDescent = 0;
154 	_trackMin = NAN;
155 	_trackMax = NAN;
156 	_routeMin = NAN;
157 	_routeMax = NAN;
158 
159 	GraphTab::clear();
160 }
161 
setYUnits(Units units)162 void ElevationGraph::setYUnits(Units units)
163 {
164 	if (units == Metric) {
165 		GraphView::setYUnits(tr("m"));
166 		setYScale(1);
167 	} else {
168 		GraphView::setYUnits(tr("ft"));
169 		setYScale(M2FT);
170 	}
171 }
172 
setUnits(Units units)173 void ElevationGraph::setUnits(Units units)
174 {
175 	setYUnits(units);
176 	setInfo();
177 
178 	GraphView::setUnits(units);
179 }
180 
showItems(const QList<ElevationGraphItem * > & list,bool show)181 void ElevationGraph::showItems(const QList<ElevationGraphItem *> &list,
182   bool show)
183 {
184 	for (int i = 0; i < list.size(); i++) {
185 		if (show)
186 			addGraph(list.at(i));
187 		else
188 			removeGraph(list.at(i));
189 	}
190 }
191 
showTracks(bool show)192 void ElevationGraph::showTracks(bool show)
193 {
194 	_showTracks = show;
195 
196 	showItems(_tracks, show);
197 	setInfo();
198 
199 	redraw();
200 }
201 
showRoutes(bool show)202 void ElevationGraph::showRoutes(bool show)
203 {
204 	_showRoutes = show;
205 
206 	showItems(_routes, show);
207 	setInfo();
208 
209 	redraw();
210 }
211 
ascent() const212 qreal ElevationGraph::ascent() const
213 {
214 	qreal val = 0;
215 
216 	if (_showRoutes)
217 		val += _routeAscent;
218 	if (_showTracks)
219 		val += _trackAscent;
220 
221 	return val;
222 }
223 
descent() const224 qreal ElevationGraph::descent() const
225 {
226 	qreal val = 0;
227 
228 	if (_showRoutes)
229 		val += _routeDescent;
230 	if (_showTracks)
231 		val += _trackDescent;
232 
233 	return val;
234 }
235 
max() const236 qreal ElevationGraph::max() const
237 {
238 	qreal val;
239 
240 	if (_showRoutes && _showTracks)
241 		val = nMax(_routeMax, _trackMax);
242 	else if (_showTracks)
243 		val = _trackMax;
244 	else if (_showRoutes)
245 		val = _routeMax;
246 	else
247 		val = NAN;
248 
249 	return val;
250 }
251 
min() const252 qreal ElevationGraph::min() const
253 {
254 	qreal val;
255 
256 	if (_showRoutes && _showTracks)
257 		val = nMin(_routeMin, _trackMin);
258 	else if (_showTracks)
259 		val = _trackMin;
260 	else if (_showRoutes)
261 		val = _routeMin;
262 	else
263 		val = NAN;
264 
265 	return val;
266 }
267