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 << ""; + oss << ""; + oss << ""; + row++; + } + oss << "
" + m->name().toStdString() << ""; + if (m->units(metricUnits) == "seconds") + oss << time_to_string(m->value(metricUnits)).toStdString(); + else + { + oss << m->value(metricUnits); + oss << " " << m->units(metricUnits).toStdString(); + } + 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: