mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	[Dirk Hohndel: extracted from a larger commit from Jan] Signed-off-by: jan Iversen <jan@casacondor.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
		
			
				
	
	
		
			189 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| #include "divesummary.h"
 | |
| #include "core/qthelper.h"
 | |
| #include "core/settings/qPrefUnit.h"
 | |
| 
 | |
| #include <QDateTime>
 | |
| 
 | |
| QStringList diveSummary::diveSummaryText;
 | |
| 
 | |
| timestamp_t diveSummary::firstDive, diveSummary::lastDive;
 | |
| int diveSummary::dives[2], diveSummary::divesEAN[2], diveSummary::divesDeep[2], diveSummary::diveplans[2];
 | |
| long diveSummary::divetime[2], diveSummary::depth[2];
 | |
| long diveSummary::divetimeMax[2], diveSummary::depthMax[2], diveSummary::sacMin[2], diveSummary::sacMax[2];
 | |
| long diveSummary::totalSACTime[2], diveSummary::totalSacVolume[2];
 | |
| 
 | |
| void diveSummary::summaryCalculation(int primaryPeriod, int secondaryPeriod)
 | |
| {
 | |
| 	QDateTime localTime;
 | |
| 
 | |
| 	// Calculate Start of the 2 periods.
 | |
| 	timestamp_t now, primaryStart, secondaryStart;
 | |
| 	now = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset();
 | |
| 	primaryStart = (primaryPeriod == 0) ? 0 : now - primaryPeriod * 30 * 24 * 60 * 60;
 | |
| 	secondaryStart = (secondaryPeriod == 0) ? 0 : now - secondaryPeriod * 30 * 24 * 60 * 60;
 | |
| 
 | |
| 	// Loop over all dives and sum up data
 | |
| 	loopDives(primaryStart, secondaryStart);
 | |
| 
 | |
| 	// prepare stringlist
 | |
| 	diveSummaryText.clear();
 | |
| 	diveSummaryText << "??" << "??" << QObject::tr("no dives in period") << QObject::tr("no divies in period")  << "??" <<
 | |
| 						 "??" << "??" << "??" <<
 | |
| 						 "?:??" << "?:??" << "?:??" <<
 | |
| 						 "?:??" << "?:??" << "?:??" <<
 | |
| 						 "??" << "??" << "??" << "??" << "??" <<
 | |
| 						 "??" << "??" << "??" << "??" << "??" << "??" << "??";
 | |
| 
 | |
| 	// set oldest/newest date
 | |
| 	if (firstDive) {
 | |
| 		localTime = QDateTime::fromMSecsSinceEpoch(1000 * firstDive, Qt::UTC);
 | |
| 		localTime.setTimeSpec(Qt::UTC);
 | |
| 		diveSummaryText[0] = QStringLiteral("%1").arg(localTime.date().toString(prefs.date_format_short));
 | |
| 	}
 | |
| 	if (lastDive) {
 | |
| 		localTime = QDateTime::fromMSecsSinceEpoch(1000 * lastDive, Qt::UTC);
 | |
| 		localTime.setTimeSpec(Qt::UTC);
 | |
| 		diveSummaryText[1] = QStringLiteral("%1").arg(localTime.date().toString(prefs.date_format_short));
 | |
| 	}
 | |
| 
 | |
| 	// and add data
 | |
| 	buildStringList(0);
 | |
| 	buildStringList(1);
 | |
| }
 | |
| 
 | |
| void diveSummary::loopDives(timestamp_t primaryStart, timestamp_t secondaryStart)
 | |
| {
 | |
| 	struct dive *dive;
 | |
| 	int i;
 | |
| 
 | |
| 	// Clear summary data
 | |
| 	firstDive = lastDive = 0;
 | |
| 	dives[0] = dives[1] = divesEAN[0] = divesEAN[1] = 0;
 | |
| 	divesDeep[0] = divesDeep[1] = diveplans[0] = diveplans[1] = 0;
 | |
| 	divetime[0] = divetime[1] = depth[0] = depth[1] = 0;
 | |
| 	divetimeMax[0] = divetimeMax[1] = depthMax[0] = depthMax[1] = 0;
 | |
| 	sacMin[0] = sacMin[1] = 99999;
 | |
| 	sacMax[0] = sacMax[1] = 0;
 | |
| 	totalSACTime[0] = totalSACTime[1] = 0;
 | |
| 	totalSacVolume[0] = totalSacVolume[1] = 0;
 | |
| 
 | |
| 	for_each_dive (i, dive) {
 | |
| 		// remember time of oldest and newest dive
 | |
| 		if (i == 0)
 | |
| 			firstDive = dive->when;
 | |
| 		if (dive->when > lastDive)
 | |
| 			lastDive = dive->when;
 | |
| 
 | |
| 		// check if dive is newer than primaryStart (add to first column)
 | |
| 		if (dive->when > primaryStart) {
 | |
| 			if (is_dc_planner(&dive->dc))
 | |
| 				diveplans[0]++;
 | |
| 			else
 | |
| 				calculateDive(0, dive);
 | |
| 		}
 | |
| 
 | |
| 		// check if dive is newer than secondaryStart (add to second column)
 | |
| 		if (dive->when > secondaryStart) {
 | |
| 			if (is_dc_planner(&dive->dc))
 | |
| 				diveplans[1]++;
 | |
| 			else
 | |
| 				calculateDive(1, dive);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void diveSummary::calculateDive(int inx, struct dive *dive)
 | |
| {
 | |
| 	// one more real dive
 | |
| 	dives[inx]++;
 | |
| 
 | |
| 	// sum dive in minutes and check for new max.
 | |
| 	divetime[inx] += dive->duration.seconds;
 | |
| 	if (dive->duration.seconds > divetimeMax[inx])
 | |
| 		divetimeMax[inx] = dive->duration.seconds;
 | |
| 
 | |
| 	// sum depth in meters, check for new max. and if dive is a deep dive
 | |
| 	depth[inx] += dive->maxdepth.mm;
 | |
| 	if (dive->maxdepth.mm > depthMax[inx])
 | |
| 		depthMax[inx] = dive->maxdepth.mm;
 | |
| 	if (dive->maxdepth.mm > 39000)
 | |
| 		divesDeep[inx]++;
 | |
| 
 | |
| 	// sum SAC, check for new min/max.
 | |
| 	if (dive->sac) {
 | |
| 		totalSACTime[inx] += dive->duration.seconds;
 | |
| 		totalSacVolume[inx] += dive->sac * dive->duration.seconds;
 | |
| 		if (dive->sac < sacMin[inx])
 | |
| 			sacMin[inx] = dive->sac;
 | |
| 		if (dive->sac > sacMax[inx])
 | |
| 			sacMax[inx] = dive->sac;
 | |
| 	}
 | |
| 
 | |
| 	// EAN dive ?
 | |
| 	for (int j = 0; j < dive->cylinders.nr; ++j) {
 | |
| 		if (dive->cylinders.cylinders[j].gasmix.o2.permille > 210) {
 | |
| 			divesEAN[inx]++;
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static QString timeString(long duration)
 | |
| {
 | |
| 	long hours = duration / 3600;
 | |
| 	long minutes = (duration - hours * 3600) / 60;
 | |
| 	if (hours >= 100)
 | |
| 		return QStringLiteral("%1h").arg(hours);
 | |
| 	else
 | |
| 		return QStringLiteral("%1:%2").arg(hours).arg(minutes, 2, 10, QChar('0'));
 | |
| }
 | |
| 
 | |
| static QString depthString(long depth)
 | |
| {
 | |
| 	return QString("%1").arg((qPrefUnits::length() == units::METERS) ? depth / 1000 : lrint(mm_to_feet(depth)));
 | |
| }
 | |
| 
 | |
| static QString volumeString(long volume)
 | |
| {
 | |
| 	return QString("%1").arg((qPrefUnits::volume() == units::LITER) ? volume / 1000 : round(100.0 * ml_to_cuft(volume)) / 100.0);
 | |
| }
 | |
| 
 | |
| void diveSummary::buildStringList(int inx)
 | |
| {
 | |
| 	if (!dives[inx]) {
 | |
| 		diveSummaryText[2+inx] = QObject::tr("no dives in period");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	// dives
 | |
| 	diveSummaryText[2+inx] = QStringLiteral("%1").arg(dives[inx]);
 | |
| 	diveSummaryText[4+inx] = QStringLiteral("%1").arg(divesEAN[inx]);
 | |
| 	diveSummaryText[6+inx] = QStringLiteral("%1").arg(divesDeep[inx]);
 | |
| 
 | |
| 	// time
 | |
| 	diveSummaryText[8+inx] = timeString(divetime[inx]);
 | |
| 	diveSummaryText[10+inx] = timeString(divetimeMax[inx]);
 | |
| 	diveSummaryText[12+inx] = timeString(divetime[inx] / dives[inx]);
 | |
| 
 | |
| 	// depth
 | |
| 	QString unitText = (qPrefUnits::length() == units::METERS) ? " m" : " ft";
 | |
| 	diveSummaryText[14+inx] = depthString(depthMax[inx]) + unitText;
 | |
| 	diveSummaryText[16+inx] = depthString(depth[inx] / dives[inx]) + unitText;
 | |
| 
 | |
| 	// SAC
 | |
| 	unitText = (qPrefUnits::volume() == units::LITER) ? " l/min" : " cuft/min";
 | |
| 	diveSummaryText[18+inx] = volumeString(sacMin[inx]) + unitText;
 | |
| 	diveSummaryText[20+inx] = volumeString(sacMax[inx]) + unitText;
 | |
| 
 | |
| 	// finally the weighted average
 | |
| 	if (totalSACTime[inx]) {
 | |
| 		long avgSac = totalSacVolume[inx] / totalSACTime[inx];
 | |
| 		diveSummaryText[22+inx] = volumeString(avgSac) + unitText;
 | |
| 	} else {
 | |
| 		diveSummaryText[22+inx] = QObject::tr("no dives");
 | |
| 	}
 | |
| 
 | |
| 	// Diveplan(s)
 | |
| 	diveSummaryText[24+inx] = QStringLiteral("%1").arg(diveplans[inx]);
 | |
| }
 |