diff --git a/src/GoogleMapControl.cpp b/src/GoogleMapControl.cpp index 878cf769d..9233dffad 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(); } }; @@ -320,7 +323,7 @@ void GoogleMapControl::createHtml() << " {size: new GSize(" << width << "," << height << ") } );" << endl << "map.setUIToDefault()" << endl << CreatePolyLine() << endl - << CreateIntervalMarkers() << endl + << CreateMarkers() << endl << "var sw = new GLatLng(" << minLat << "," << minLon << ");" << endl << "var ne = new GLatLng(" << maxLat << "," << maxLon << ");" << endl << "var bounds = new GLatLngBounds(sw,ne);" << endl @@ -419,76 +422,137 @@ void GoogleMapControl::CreateSubPolyLine(const std::vector &point oss << "map.addOverlay (polyline);" << endl; } - -string GoogleMapControl::CreateIntervalMarkers() +string GoogleMapControl::CreateIntervalMarkers(RideItem *rideItem) { - bool useMetricUnits = (appsettings->value(this, GC_UNIT).toString() == "Metric"); + ostringstream oss; + RideFile *ride = rideItem->ride(); + if(ride->intervals().size() == 0) + return ""; + + bool metricUnits = (appsettings->value(this, GC_UNIT).toString() == "Metric"); + + QStringList intervalMetrics = appsettings->value(this, + GC_SETTINGS_INTERVAL_METRICS, + GC_SETTINGS_INTERVAL_METRICS_DEFAULT).toString().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(main, &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() +{ ostringstream oss; oss.precision(6); oss.setf(ios::fixed,ios::floatfield); + RideItem *ride = myRideItem; + + // 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 + bool metricUnits = (appsettings->value(main, GC_UNIT, "Metric").toString() == "Metric"); - QTime time; - time = time.addSecs(secs); + QStringList intervalMetrics = appsettings->value(this, + GC_SETTINGS_INTERVAL_METRICS, + GC_SETTINGS_INTERVAL_METRICS_DEFAULT).toString().split(","); - AvgHR avgHr = for_each(intervalPoints.begin(), - intervalPoints.end(), - AvgHR()); - AvgPower avgPower = for_each(intervalPoints.begin(), - intervalPoints.end(), - AvgPower()); + QHash metrics = + RideMetric::computeMetrics(main, 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(); +} - 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 3fc743c18..dc6a8f9db 100644 --- a/src/GoogleMapControl.h +++ b/src/GoogleMapControl.h @@ -54,8 +54,12 @@ G_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(); + 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