From 93ad436c6ae55a446e357dfdf756df955d1e5fa2 Mon Sep 17 00:00:00 2001
From: Greg Lonnon
Date: Sun, 2 Jan 2011 07:16:14 -0700
Subject: [PATCH] changes to the markers in google maps.
blue marker = start of ride
red marker = end of ride
green markers = interval markers.
interval markers has the interval metrics displayed.
end marker has the ride summary displayed.
Fixes #169.
---
src/GoogleMapControl.cpp | 204 ++++++++++++++++++++++++++-------------
src/GoogleMapControl.h | 8 +-
2 files changed, 144 insertions(+), 68 deletions(-)
diff --git a/src/GoogleMapControl.cpp b/src/GoogleMapControl.cpp
index 9b11b6014..abfdbb686 100644
--- a/src/GoogleMapControl.cpp
+++ b/src/GoogleMapControl.cpp
@@ -23,11 +23,11 @@
#include "Zones.h"
#include "Settings.h"
#include "Units.h"
+#include "TimeUtils.h"
#include
-#include
-#include
+
#include
#include
#include
@@ -115,7 +115,10 @@ namespace gm
totalHR += rfp.hr;
samples++;
}
- int HR() { return totalHR / samples; }
+ int HR() {
+ if(samples == 0) return 0;
+ return totalHR / samples;
+ }
operator int() { return HR(); }
};
@@ -238,7 +241,7 @@ void GoogleMapControl::loadRide()
if(newRideToLoad == true)
{
- createHtml();
+ createHtml(current);
newRideToLoad = false;
loadingPage = true;
@@ -257,7 +260,7 @@ void GoogleMapControl::loadRide()
}
}
-void GoogleMapControl::createHtml()
+void GoogleMapControl::createHtml(RideItem *ride)
{
currentPage.str("");
double minLat, minLon, maxLat, maxLon;
@@ -305,7 +308,7 @@ void GoogleMapControl::createHtml()
<< " {size: new GSize(" << width << "," << height << ") } );" << endl
<< "map.setUIToDefault()" << endl
<< CreatePolyLine() << endl
- << CreateIntervalMarkers() << endl
+ << CreateMarkers(ride) << endl
<< "var sw = new GLatLng(" << minLat << "," << minLon << ");" << endl
<< "var ne = new GLatLng(" << maxLat << "," << maxLon << ");" << endl
<< "var bounds = new GLatLngBounds(sw,ne);" << endl
@@ -404,77 +407,146 @@ void GoogleMapControl::CreateSubPolyLine(const std::vector &point
oss << "map.addOverlay (polyline);" << endl;
}
-
-string GoogleMapControl::CreateIntervalMarkers()
+string GoogleMapControl::CreateIntervalMarkers(RideItem *rideItem)
{
- bool useMetricUnits = (GetApplicationSettings()->value(GC_UNIT).toString()
- == "Metric");
+ ostringstream oss;
+ RideFile *ride = rideItem->ride();
+ if(ride->intervals().size() == 0)
+ return "";
+
+ boost::shared_ptr settings = GetApplicationSettings();
+ QVariant unit = settings->value(GC_UNIT);
+ bool metricUnits = (unit.toString() == "Metric");
+
+ QString s;
+ if (settings->contains(GC_SETTINGS_INTERVAL_METRICS))
+ s = settings->value(GC_SETTINGS_INTERVAL_METRICS).toString();
+ else
+ s = GC_SETTINGS_INTERVAL_METRICS_DEFAULT;
+
+
+ QStringList intervalMetrics = s.split(",");
+
+ int row = 0;
+ foreach (RideFileInterval interval, ride->intervals()) {
+ // create a temp RideFile to be used to figure out the metrics for the interval
+ RideFile f(ride->startTime(), ride->recIntSecs());
+ for (int i = ride->intervalBegin(interval); i < ride->dataPoints().size(); ++i) {
+ const RideFilePoint *p = ride->dataPoints()[i];
+ if (p->secs >= interval.stop)
+ break;
+ f.appendPoint(p->secs, p->cad, p->hr, p->km, p->kph, p->nm,
+ p->watts, p->alt, p->lon, p->lat, p->headwind, 0);
+ }
+ if (f.dataPoints().size() == 0) {
+ // Interval empty, do not compute any metrics
+ continue;
+ }
+
+ QHash metrics =
+ RideMetric::computeMetrics(&f, parent->zones(), parent->hrZones(), intervalMetrics);
+
+ string html = CreateIntervalHtml(metrics,intervalMetrics,interval.name,metricUnits);
+ row++;
+ oss << CreateMarker(row,f.dataPoints().front()->lat,f.dataPoints().front()->lon,html);
+ }
+ return oss.str();
+}
+
+string GoogleMapControl::CreateIntervalHtml(QHash &metrics, QStringList &intervalMetrics,
+ QString &intervalName, bool metricUnits)
+{
+ ostringstream oss;
+
+ oss << "" << intervalName.toStdString() << "
";
+ oss << "";
+ int row = 0;
+ foreach (QString symbol, intervalMetrics) {
+ RideMetricPtr m = metrics.value(symbol);
+ if(m == NULL)
+ continue;
+ if (row % 2)
+ oss << "";
+ else {
+ QColor color = QApplication::palette().alternateBase().color();
+ color = QColor::fromHsv(color.hue(), color.saturation() * 2, color.value());
+ oss << "
";
+ }
+ oss.setf(ios::fixed);
+ oss.precision(m->precision());
+ oss << "| " + m->name().toStdString() << " | ";
+ oss << "";
+ if (m->units(metricUnits) == "seconds")
+ oss << time_to_string(m->value(metricUnits)).toStdString();
+ else
+ {
+ oss << m->value(metricUnits);
+ oss << " " << m->units(metricUnits).toStdString();
+ }
+ oss <<" | ";
+ oss << "
";
+ row++;
+ }
+ oss << "
";
+ return oss.str();
+}
+
+string GoogleMapControl::CreateMarkers(RideItem *ride)
+{
ostringstream oss;
oss.precision(6);
oss.setf(ios::fixed,ios::floatfield);
+ // start marker
oss << "var marker;" << endl;
- int currentInterval = 0;
- std::vector intervalPoints;
- BOOST_FOREACH(RideFilePoint rfp, rideData)
- {
- intervalPoints.push_back(rfp);
- if(currentInterval < rfp.interval)
- {
- // want to see avg power, avg speed, alt changes, avg hr
- double distance = intervalPoints.back().km -
- intervalPoints.front().km ;
- distance = (useMetricUnits ? distance : distance * MILES_PER_KM);
+ oss << "var blueIcon = new GIcon(G_DEFAULT_ICON);" << endl;
+ oss << "blueIcon.image = \"http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/blank.png\"" << endl;
+ oss << "markerOptions = { icon:blueIcon };" << endl;
+ oss << "marker = new GMarker(new GLatLng(";
+ oss << rideData.front().lat << "," << rideData.front().lon << "),blueIcon);" << endl;
+ oss << "marker.bindInfoWindowHtml(\"Start
\");" << endl;
+ oss << "map.addOverlay(marker);" << endl;
- int secs = intervalPoints.back().secs -
- intervalPoints.front().secs;
+ oss << CreateIntervalMarkers(ride);
- double avgSpeed = (distance/((double)secs)) * 3600;
+ // end marker
+ boost::shared_ptr settings = GetApplicationSettings();
+ QVariant unit = settings->value(GC_UNIT);
+ bool metricUnits = (unit.toString() == "Metric");
- QTime time;
- time = time.addSecs(secs);
+ QString s;
+ if (settings->contains(GC_SETTINGS_INTERVAL_METRICS))
+ s = settings->value(GC_SETTINGS_INTERVAL_METRICS).toString();
+ else
+ s = GC_SETTINGS_INTERVAL_METRICS_DEFAULT;
+ QStringList intervalMetrics = s.split(",");
+ QHash metrics =
+ RideMetric::computeMetrics(ride->ride(), parent->zones(), parent->hrZones(), intervalMetrics);
+ QString name = "Ride Summary";
+ string html = CreateIntervalHtml(metrics,intervalMetrics,name,metricUnits);
+ oss << "var redIcon = new GIcon(G_DEFAULT_ICON);" << endl;
+ oss << "redIcon.image = \"http://gmaps-samples.googlecode.com/svn/trunk/markers/red/blank.png\"" << endl;
+ oss << "markerOptions = { icon:redIcon };" << endl;
+ oss << "marker = new GMarker(new GLatLng(";
+ oss << rideData.back().lat << "," << rideData.back().lon << "),redIcon);" << endl;
+ oss << "marker.bindInfoWindowHtml(\""<< html << "\");" << endl;
+ oss << "map.addOverlay(marker);" << endl;
+ return oss.str();
+}
- AvgHR avgHr = for_each(intervalPoints.begin(),
- intervalPoints.end(),
- AvgHR());
- AvgPower avgPower = for_each(intervalPoints.begin(),
- intervalPoints.end(),
- AvgPower());
-
- int altGained =ceil(for_each(intervalPoints.begin(),
- intervalPoints.end(),
- AltGained()));
- altGained = ceil((useMetricUnits ? altGained :
- altGained * FEET_PER_METER));
- oss.precision(6);
- oss << "marker = new GMarker(new GLatLng( ";
- oss<< rfp.lat << "," << rfp.lon << "));" << endl;
- oss << "marker.bindInfoWindowHtml(" <Lap: " << currentInterval << "
" ;
- oss.precision(1);
- oss << "Distance: " << distance << " "
- << (useMetricUnits ? "KM" : "Miles") << "
" ;
- oss << "Time: " << time.toString().toStdString() << "
";
- oss << "Avg Speed>: " << avgSpeed << " "
- << (useMetricUnits ? tr("KPH") : tr("MPH")).toStdString()
- << "
";
- if(avgHr != 0) {
- oss << "Avg HR: " << avgHr << "
";
- }
- if(avgPower != 0)
- {
- oss << "Avg Power: " << avgPower << " Watts
";
- }
- oss << "Alt Gained: " << altGained << " "
- << (useMetricUnits ? tr("Meters") : tr("Feet")).toStdString()
- << "
";
- oss << "\");" << endl;
- oss << "map.addOverlay(marker);" << endl;
- currentInterval = rfp.interval;
- intervalPoints.clear();
- }
- }
+std::string GoogleMapControl::CreateMarker(int number, double lat, double lon, string &html)
+{
+ ostringstream oss;
+ oss.precision(6);
+ oss << "intervalIcon = new GIcon(G_DEFAULT_ICON);" << endl;
+ oss << "intervalIcon.image = \"http://gmaps-samples.googlecode.com/svn/trunk/markers/green/marker" << number << ".png\"" << endl;
+ oss << "markerOptions = { icon:intervalIcon };" << endl;
+ oss << "marker = new GMarker(new GLatLng( ";
+ oss<< lat << "," << lon << "),intervalIcon);" << endl;
+ oss << "marker.bindInfoWindowHtml(\"" << html << "\");";
+ oss.precision(1);
+ oss << "map.addOverlay(marker);" << endl;
return oss.str();
}
diff --git a/src/GoogleMapControl.h b/src/GoogleMapControl.h
index 809107d79..2347d81d9 100644
--- a/src/GoogleMapControl.h
+++ b/src/GoogleMapControl.h
@@ -51,8 +51,12 @@ Q_OBJECT
std::ostringstream &oss,
int avgPower);
std::string CreateMapToolTipJavaScript();
- std::string CreateIntervalMarkers();
+ std::string CreateIntervalHtml(QHash &metrics, QStringList &intervalMetrics,
+ QString &intervalName, bool useMetrics);
+ std::string CreateMarkers(RideItem *ride);
+ std::string CreateIntervalMarkers(RideItem *ride);
void loadRide();
+ std::string CreateMarker(int number, double lat, double lon, std::string &html);
// the web browser is loading a page, do NOT start another load
bool loadingPage;
// the ride has changed, load a new page
@@ -78,7 +82,7 @@ Q_OBJECT
void loadFinished(bool);
protected:
- void createHtml();
+ void createHtml(RideItem *);
void resizeEvent(QResizeEvent *);
public: