mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	profile: clip DiveProfileItems
Avoid "overshooting" of the profile items by linearly clipping the first and last segment to the boundaries of the time-axis. Sadly, quite a lot of code, because every profile item is slightly different. In particular the pressure-segment handling was rewritten. It now stores the begin and end of each segment to draw the appropriate text items. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
		
							parent
							
								
									56f6e5051f
								
							
						
					
					
						commit
						073059f5ab
					
				
					 2 changed files with 216 additions and 116 deletions
				
			
		| 
						 | 
					@ -26,6 +26,44 @@ void AbstractProfilePolygonItem::clear()
 | 
				
			||||||
	texts.clear();
 | 
						texts.clear();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static std::pair<double,double> clip(double x1, double y1, double x2, double y2, double x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						double rel = fabs(x2 - x1) > 1e-10 ? (x - x1) / (x2 - x1) : 0.5;
 | 
				
			||||||
 | 
						return { x, (y2 - y1) * rel + y1 };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AbstractProfilePolygonItem::clipStart(double &x, double &y, double next_x, double next_y) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (x < hAxis.minimum())
 | 
				
			||||||
 | 
							std::tie(x, y) = clip(x, y, next_x, next_y, hAxis.minimum());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AbstractProfilePolygonItem::clipStop(double &x, double &y, double prev_x, double prev_y) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (x > hAxis.maximum())
 | 
				
			||||||
 | 
							std::tie(x, y) = clip(prev_x, prev_y, x, y, hAxis.maximum());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::pair<double, double> AbstractProfilePolygonItem::getPoint(int i) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						double x = dataModel.index(i, hDataColumn).data().toReal();
 | 
				
			||||||
 | 
						double y = dataModel.index(i, vDataColumn).data().toReal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Do clipping of first and last value
 | 
				
			||||||
 | 
						if (i == from && i < to) {
 | 
				
			||||||
 | 
							double next_x = dataModel.index(i+1, hDataColumn).data().toReal();
 | 
				
			||||||
 | 
							double next_y = dataModel.index(i+1, vDataColumn).data().toReal();
 | 
				
			||||||
 | 
							clipStart(x, y, next_x, next_y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (i == to - 1 && i > 0) {
 | 
				
			||||||
 | 
							double prev_x = dataModel.index(i-1, hDataColumn).data().toReal();
 | 
				
			||||||
 | 
							double prev_y = dataModel.index(i-1, vDataColumn).data().toReal();
 | 
				
			||||||
 | 
							clipStop(x, y, prev_x, prev_y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return { x, y };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AbstractProfilePolygonItem::makePolygon(int fromIn, int toIn)
 | 
					void AbstractProfilePolygonItem::makePolygon(int fromIn, int toIn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	from = fromIn;
 | 
						from = fromIn;
 | 
				
			||||||
| 
						 | 
					@ -38,8 +76,8 @@ void AbstractProfilePolygonItem::makePolygon(int fromIn, int toIn)
 | 
				
			||||||
	// to our coordinates, store. no painting is done here.
 | 
						// to our coordinates, store. no painting is done here.
 | 
				
			||||||
	QPolygonF poly;
 | 
						QPolygonF poly;
 | 
				
			||||||
	for (int i = from; i < to; i++) {
 | 
						for (int i = from; i < to; i++) {
 | 
				
			||||||
		double horizontalValue = dataModel.index(i, hDataColumn).data().toReal();
 | 
							auto [horizontalValue, verticalValue] = getPoint(i);
 | 
				
			||||||
		double verticalValue = dataModel.index(i, vDataColumn).data().toReal();
 | 
					
 | 
				
			||||||
		if (i == from) {
 | 
							if (i == from) {
 | 
				
			||||||
			QPointF point(hAxis.posAtValue(horizontalValue), vAxis.posAtValue(0.0));
 | 
								QPointF point(hAxis.posAtValue(horizontalValue), vAxis.posAtValue(0.0));
 | 
				
			||||||
			poly.append(point);
 | 
								poly.append(point);
 | 
				
			||||||
| 
						 | 
					@ -175,7 +213,7 @@ void DiveHeartrateItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
	from = fromIn;
 | 
						from = fromIn;
 | 
				
			||||||
	to = toIn;
 | 
						to = toIn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int last = -300, last_printed_hr = 0, sec = 0;
 | 
						int last = -300, last_printed_hr = 0;
 | 
				
			||||||
	struct sec_hr {
 | 
						struct sec_hr {
 | 
				
			||||||
		int sec;
 | 
							int sec;
 | 
				
			||||||
		int hr;
 | 
							int hr;
 | 
				
			||||||
| 
						 | 
					@ -187,11 +225,12 @@ void DiveHeartrateItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
	// Ignore empty values. a heart rate of 0 would be a bad sign.
 | 
						// Ignore empty values. a heart rate of 0 would be a bad sign.
 | 
				
			||||||
	QPolygonF poly;
 | 
						QPolygonF poly;
 | 
				
			||||||
	for (int i = from; i < to; i++) {
 | 
						for (int i = from; i < to; i++) {
 | 
				
			||||||
		int hr = dataModel.index(i, vDataColumn).data().toInt();
 | 
							auto [sec_double, hr_double] = getPoint(i);
 | 
				
			||||||
 | 
							int hr = lrint(hr_double);
 | 
				
			||||||
		if (!hr)
 | 
							if (!hr)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		sec = dataModel.index(i, hDataColumn).data().toInt();
 | 
							int sec = lrint(sec_double);
 | 
				
			||||||
		QPointF point(hAxis.posAtValue(sec), vAxis.posAtValue(hr));
 | 
							QPointF point(hAxis.posAtValue(sec_double), vAxis.posAtValue(hr_double));
 | 
				
			||||||
		poly.append(point);
 | 
							poly.append(point);
 | 
				
			||||||
		if (hr == hist[2].hr)
 | 
							if (hr == hist[2].hr)
 | 
				
			||||||
			// same as last one, no point in looking at printing
 | 
								// same as last one, no point in looking at printing
 | 
				
			||||||
| 
						 | 
					@ -263,7 +302,7 @@ void DiveTemperatureItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
	from = fromIn;
 | 
						from = fromIn;
 | 
				
			||||||
	to = toIn;
 | 
						to = toIn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int last = -300, last_printed_temp = 0, sec = 0, last_valid_temp = 0;
 | 
						double last = -300.0, last_printed_temp = 0.0, last_valid_temp = 0.0, sec = 0.0;
 | 
				
			||||||
	std::vector<std::pair<int, int>> textItems;
 | 
						std::vector<std::pair<int, int>> textItems;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	qDeleteAll(texts);
 | 
						qDeleteAll(texts);
 | 
				
			||||||
| 
						 | 
					@ -271,35 +310,34 @@ void DiveTemperatureItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
	// Ignore empty values. things do not look good with '0' as temperature in kelvin...
 | 
						// Ignore empty values. things do not look good with '0' as temperature in kelvin...
 | 
				
			||||||
	QPolygonF poly;
 | 
						QPolygonF poly;
 | 
				
			||||||
	for (int i = from; i < to; i++) {
 | 
						for (int i = from; i < to; i++) {
 | 
				
			||||||
		int mkelvin = dataModel.index(i, vDataColumn).data().toInt();
 | 
							auto [sec, mkelvin] = getPoint(i);
 | 
				
			||||||
		if (!mkelvin)
 | 
							if (mkelvin < 1.0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		last_valid_temp = mkelvin;
 | 
					 | 
				
			||||||
		sec = dataModel.index(i, hDataColumn).data().toInt();
 | 
					 | 
				
			||||||
		QPointF point(hAxis.posAtValue(sec), vAxis.posAtValue(mkelvin));
 | 
							QPointF point(hAxis.posAtValue(sec), vAxis.posAtValue(mkelvin));
 | 
				
			||||||
		poly.append(point);
 | 
							poly.append(point);
 | 
				
			||||||
 | 
							last_valid_temp = sec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* don't print a temperature
 | 
							/* don't print a temperature
 | 
				
			||||||
		 * if it's been less than 5min and less than a 2K change OR
 | 
							 * if it's been less than 5min and less than a 2K change OR
 | 
				
			||||||
		 * if it's been less than 2min OR if the change from the
 | 
							 * if it's been less than 2min OR if the change from the
 | 
				
			||||||
		 * last print is less than .4K (and therefore less than 1F) */
 | 
							 * last print is less than .4K (and therefore less than 1F) */
 | 
				
			||||||
		if (((sec < last + 300) && (abs(mkelvin - last_printed_temp) < 2000)) ||
 | 
							if (((sec < last + 300.0) && (fabs(mkelvin - last_printed_temp) < 2000.0)) ||
 | 
				
			||||||
		    (sec < last + 120) ||
 | 
							    (sec < last + 120.0) ||
 | 
				
			||||||
		    (abs(mkelvin - last_printed_temp) < 400))
 | 
							    (fabs(mkelvin - last_printed_temp) < 400.0))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		last = sec;
 | 
							last = sec;
 | 
				
			||||||
		if (mkelvin > 200000)
 | 
							if (mkelvin > 200000.0)
 | 
				
			||||||
			textItems.push_back({ sec, mkelvin });
 | 
								textItems.push_back({ static_cast<int>(sec), static_cast<int>(mkelvin) });
 | 
				
			||||||
		last_printed_temp = mkelvin;
 | 
							last_printed_temp = mkelvin;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setPolygon(poly);
 | 
						setPolygon(poly);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* it would be nice to print the end temperature, if it's
 | 
						/* print the end temperature, if it's different or if the
 | 
				
			||||||
	* different or if the last temperature print has been more
 | 
						 * last temperature print has been more than a quarter of the
 | 
				
			||||||
	* than a quarter of the dive back */
 | 
						 * dive back */
 | 
				
			||||||
	if (last_valid_temp > 200000 &&
 | 
						if (last_valid_temp > 200000.0 &&
 | 
				
			||||||
	    ((abs(last_valid_temp - last_printed_temp) > 500) || ((double)last / (double)sec < 0.75))) {
 | 
						    ((fabs(last_valid_temp - last_printed_temp) > 500.0) || (last < 0.75 * sec))) {
 | 
				
			||||||
		textItems.push_back({ sec, last_valid_temp });
 | 
							textItems.push_back({ static_cast<int>(sec), static_cast<int>(last_valid_temp) });
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (size_t i = 0; i < textItems.size(); ++i) {
 | 
						for (size_t i = 0; i < textItems.size(); ++i) {
 | 
				
			||||||
| 
						 | 
					@ -340,7 +378,30 @@ DiveMeanDepthItem::DiveMeanDepthItem(const DivePlotDataModel &model, const DiveC
 | 
				
			||||||
	pen.setCosmetic(true);
 | 
						pen.setCosmetic(true);
 | 
				
			||||||
	pen.setWidth(2);
 | 
						pen.setWidth(2);
 | 
				
			||||||
	setPen(pen);
 | 
						setPen(pen);
 | 
				
			||||||
	lastRunningSum = 0.0;
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Apparently, there can be samples without mean depth? If not, remove these functions.
 | 
				
			||||||
 | 
					std::pair<double,double> DiveMeanDepthItem::getMeanDepth(int i) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						for ( ; i >= 0; --i) {
 | 
				
			||||||
 | 
							const plot_data &entry = dataModel.data().entry[i];
 | 
				
			||||||
 | 
							if (entry.running_sum > 0)
 | 
				
			||||||
 | 
								return { static_cast<double>(entry.sec),
 | 
				
			||||||
 | 
									 static_cast<double>(entry.running_sum) / entry.sec };
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return { 0.0, 0.0 };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::pair<double,double> DiveMeanDepthItem::getNextMeanDepth(int first) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int last = dataModel.data().nr;
 | 
				
			||||||
 | 
						for (int i = first + 1; i < last;  ++i) {
 | 
				
			||||||
 | 
							const plot_data &entry = dataModel.data().entry[i];
 | 
				
			||||||
 | 
							if (entry.running_sum > 0)
 | 
				
			||||||
 | 
								return { static_cast<double>(entry.sec),
 | 
				
			||||||
 | 
									 static_cast<double>(entry.running_sum) / entry.sec };
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return getMeanDepth(first);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DiveMeanDepthItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
					void DiveMeanDepthItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
| 
						 | 
					@ -348,22 +409,32 @@ void DiveMeanDepthItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
	from = fromIn;
 | 
						from = fromIn;
 | 
				
			||||||
	to = toIn;
 | 
						to = toIn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	double meandepthvalue = 0.0;
 | 
						double prevSec = 0.0, prevMeanDepth = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QPolygonF poly;
 | 
						QPolygonF poly;
 | 
				
			||||||
	plot_data *entry = dataModel.data().entry + from;
 | 
						for (int i = from; i < to; i++) {
 | 
				
			||||||
	for (int i = from; i < to; i++, entry++) {
 | 
							auto [sec, meanDepth] = getMeanDepth(i);
 | 
				
			||||||
		// Ignore empty values
 | 
							// Ignore empty values
 | 
				
			||||||
		if (entry->running_sum == 0 || entry->sec == 0)
 | 
							if (meanDepth == 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
							if (i == from && i < to) {
 | 
				
			||||||
 | 
								auto [sec2, meanDepth2] = getNextMeanDepth(i);
 | 
				
			||||||
 | 
								if (meanDepth2 > 0.0)
 | 
				
			||||||
 | 
									clipStart(sec, meanDepth, sec2, meanDepth2);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (i == to - 1 && i > 0)
 | 
				
			||||||
 | 
								clipStop(sec, meanDepth, prevSec, prevMeanDepth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		meandepthvalue = entry->running_sum / entry->sec;
 | 
					
 | 
				
			||||||
		QPointF point(hAxis.posAtValue(entry->sec), vAxis.posAtValue(meandepthvalue));
 | 
							QPointF point(hAxis.posAtValue(sec), vAxis.posAtValue(meanDepth));
 | 
				
			||||||
		poly.append(point);
 | 
							poly.append(point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							prevSec = sec;
 | 
				
			||||||
 | 
							prevMeanDepth = meanDepth;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	lastRunningSum = meandepthvalue;
 | 
					 | 
				
			||||||
	setPolygon(poly);
 | 
						setPolygon(poly);
 | 
				
			||||||
	createTextItem();
 | 
						if (prevMeanDepth > 0.0)
 | 
				
			||||||
 | 
							createTextItem(prevSec, prevMeanDepth);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -377,15 +448,13 @@ void DiveMeanDepthItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*
 | 
				
			||||||
	painter->restore();
 | 
						painter->restore();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DiveMeanDepthItem::createTextItem()
 | 
					void DiveMeanDepthItem::createTextItem(double lastSec, double lastMeanDepth)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	plot_data *entry = dataModel.data().entry;
 | 
					 | 
				
			||||||
	int sec = to > 0 ? entry[to-1].sec : 0;
 | 
					 | 
				
			||||||
	qDeleteAll(texts);
 | 
						qDeleteAll(texts);
 | 
				
			||||||
	texts.clear();
 | 
						texts.clear();
 | 
				
			||||||
	DiveTextItem *text = new DiveTextItem(dpr, 0.8, Qt::AlignRight | Qt::AlignTop, this);
 | 
						DiveTextItem *text = new DiveTextItem(dpr, 0.8, Qt::AlignRight | Qt::AlignTop, this);
 | 
				
			||||||
	text->set(get_depth_string(lrint(lastRunningSum), true), getColor(TEMP_TEXT));
 | 
						text->set(get_depth_string(lrint(lastMeanDepth), true), getColor(TEMP_TEXT));
 | 
				
			||||||
	text->setPos(QPointF(hAxis.posAtValue(sec) + 1, vAxis.posAtValue(lastRunningSum)));
 | 
						text->setPos(QPointF(hAxis.posAtValue(lastSec) + dpr, vAxis.posAtValue(lastMeanDepth)));
 | 
				
			||||||
	texts.append(text);
 | 
						texts.append(text);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -396,21 +465,37 @@ void DiveGasPressureItem::replot(const dive *d, int fromIn, int toIn, bool in_pl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const struct plot_info *pInfo = &dataModel.data();
 | 
						const struct plot_info *pInfo = &dataModel.data();
 | 
				
			||||||
	std::vector<int> plotted_cyl(pInfo->nr_cylinders, false);
 | 
						std::vector<int> plotted_cyl(pInfo->nr_cylinders, false);
 | 
				
			||||||
	std::vector<int> last_plotted(pInfo->nr_cylinders, 0);
 | 
						std::vector<double> last_plotted(pInfo->nr_cylinders, 0.0);
 | 
				
			||||||
	std::vector<std::vector<Entry>> poly(pInfo->nr_cylinders);
 | 
						std::vector<Segment> act_segments(pInfo->nr_cylinders);
 | 
				
			||||||
	QPolygonF boundingPoly;
 | 
						QPolygonF boundingPoly;
 | 
				
			||||||
	polygons.clear();
 | 
						segments.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = from; i < to; i++) {
 | 
						for (int i = from; i < to; i++) {
 | 
				
			||||||
		const struct plot_data *entry = pInfo->entry + i;
 | 
							const struct plot_data *entry = pInfo->entry + i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
 | 
							for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
 | 
				
			||||||
			int mbar = get_plot_pressure(pInfo, i, cyl);
 | 
								double mbar = static_cast<double>(get_plot_pressure(pInfo, i, cyl));
 | 
				
			||||||
			int time = entry->sec;
 | 
								double time = static_cast<double>(entry->sec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!mbar)
 | 
								if (mbar < 1.0)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (i == from && i < to - 1) {
 | 
				
			||||||
 | 
									double mbar2 = static_cast<double>(get_plot_pressure(pInfo, i+1, cyl));
 | 
				
			||||||
 | 
									double time2 = static_cast<double>(entry[1].sec);
 | 
				
			||||||
 | 
									if (mbar2 < 1.0)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									clipStart(time, mbar, time2, mbar2);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (i == to - 1 && i > from) {
 | 
				
			||||||
 | 
									double mbar2 = static_cast<double>(get_plot_pressure(pInfo, i-1, cyl));
 | 
				
			||||||
 | 
									double time2 = static_cast<double>(entry[-1].sec);
 | 
				
			||||||
 | 
									if (mbar2 < 1.0)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									clipStop(time, mbar, time2, mbar2);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			QPointF point(hAxis.posAtValue(time), vAxis.posAtValue(mbar));
 | 
								QPointF point(hAxis.posAtValue(time), vAxis.posAtValue(mbar));
 | 
				
			||||||
			boundingPoly.push_back(point);
 | 
								boundingPoly.push_back(point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -421,46 +506,50 @@ void DiveGasPressureItem::replot(const dive *d, int fromIn, int toIn, bool in_pl
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					color = MED_GRAY_HIGH_TRANS;
 | 
										color = MED_GRAY_HIGH_TRANS;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				if (mbar < 0)
 | 
									if (mbar < 0.0)
 | 
				
			||||||
					color = MAGENTA;
 | 
										color = MAGENTA;
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					color = getPressureColor(entry->density);
 | 
										color = getPressureColor(entry->density);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (plotted_cyl[cyl]) {
 | 
								if (!act_segments[cyl].polygon.empty()) {
 | 
				
			||||||
				/* Have we used this cylinder in the last two minutes? Continue */
 | 
									/* Have we used this cylinder in the last two minutes? Continue */
 | 
				
			||||||
				if (time - last_plotted[cyl] <= 2*60) {
 | 
									if (time - act_segments[cyl].last.time <= 2*60) {
 | 
				
			||||||
					poly[cyl].push_back({ point, color });
 | 
										act_segments[cyl].polygon.push_back({ point, color });
 | 
				
			||||||
					last_plotted[cyl] = time;
 | 
										act_segments[cyl].last.time = time;
 | 
				
			||||||
 | 
										act_segments[cyl].last.pressure = mbar;
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/* Finish the previous one, start a new one */
 | 
									/* Finish the previous one, start a new one */
 | 
				
			||||||
				polygons.push_back(std::move(poly[cyl]));
 | 
									act_segments[cyl].cyl = cyl;
 | 
				
			||||||
				poly[cyl].clear();
 | 
									segments.push_back(std::move(act_segments[cyl]));
 | 
				
			||||||
 | 
									act_segments[cyl] = Segment();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			plotted_cyl[cyl] = true;
 | 
								plotted_cyl[cyl] = true;
 | 
				
			||||||
			last_plotted[cyl] = time;
 | 
								act_segments[cyl].polygon.push_back({ point, color });
 | 
				
			||||||
			poly[cyl].push_back({ point, color });
 | 
								act_segments[cyl].last.time = time;
 | 
				
			||||||
 | 
								act_segments[cyl].last.pressure = mbar;
 | 
				
			||||||
 | 
								if (act_segments[cyl].first.pressure == 0.0) {
 | 
				
			||||||
 | 
									act_segments[cyl].first.time = time;
 | 
				
			||||||
 | 
									act_segments[cyl].first.pressure = mbar;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
 | 
						for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
 | 
				
			||||||
		if (!plotted_cyl[cyl])
 | 
							if (act_segments[cyl].polygon.empty())
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		polygons.push_back(poly[cyl]);
 | 
							act_segments[cyl].cyl = cyl;
 | 
				
			||||||
 | 
							segments.push_back(std::move(act_segments[cyl]));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setPolygon(boundingPoly);
 | 
						setPolygon(boundingPoly);
 | 
				
			||||||
	qDeleteAll(texts);
 | 
						qDeleteAll(texts);
 | 
				
			||||||
	texts.clear();
 | 
						texts.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<int> seen_cyl(pInfo->nr_cylinders, false);
 | 
						// These are offset values used to print the gas labels and pressures on a
 | 
				
			||||||
	std::vector<int> last_pressure(pInfo->nr_cylinders, 0);
 | 
					 | 
				
			||||||
	std::vector<int> last_time(pInfo->nr_cylinders, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// These are offset values used to print the gas lables and pressures on a
 | 
					 | 
				
			||||||
	// dive profile at appropriate Y-coordinates. We alternate aligning the
 | 
						// dive profile at appropriate Y-coordinates. We alternate aligning the
 | 
				
			||||||
	// label and the gas pressure above and under the pressure line.
 | 
						// label and the gas pressure above and under the pressure line.
 | 
				
			||||||
	// The values are historical, and we could try to pick the over/under
 | 
						// The values are historical, and we could try to pick the over/under
 | 
				
			||||||
| 
						 | 
					@ -473,54 +562,35 @@ void DiveGasPressureItem::replot(const dive *d, int fromIn, int toIn, bool in_pl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	double labelHeight = DiveTextItem::fontHeight(dpr, 1.0);
 | 
						double labelHeight = DiveTextItem::fontHeight(dpr, 1.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = from; i < to; i++) {
 | 
						for (const Segment &segment: segments) {
 | 
				
			||||||
		const struct plot_data *entry = pInfo->entry + i;
 | 
							// Magic Y offset depending on whether we're aliging
 | 
				
			||||||
 | 
							// the top of the text or the bottom of the text to
 | 
				
			||||||
 | 
							// the pressure line.
 | 
				
			||||||
 | 
							double value_y_offset = -0.5 * dpr;
 | 
				
			||||||
 | 
							double label_y_offset = alignVar & Qt::AlignTop ? labelHeight : -labelHeight;
 | 
				
			||||||
 | 
							gasmix gas = get_cylinder(d, segment.cyl)->gasmix;
 | 
				
			||||||
 | 
							plotPressureValue(segment.first.pressure, segment.first.time, alignVar, value_y_offset);
 | 
				
			||||||
 | 
							plotGasValue(segment.first.pressure, segment.first.time, gas, alignVar, label_y_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
 | 
							// For each cylinder, on right hand side of the curve, write cylinder pressure
 | 
				
			||||||
			int mbar = get_plot_pressure(pInfo, i, cyl);
 | 
							plotPressureValue(segment.last.pressure, segment.last.time, alignVar | Qt::AlignLeft, value_y_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!mbar)
 | 
							/* Alternate alignment as we see cylinder use.. */
 | 
				
			||||||
				continue;
 | 
							alignVar ^= Qt::AlignTop | Qt::AlignBottom;
 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (!seen_cyl[cyl]) {
 | 
					 | 
				
			||||||
				// Magic Y offset depending on whether we're aliging
 | 
					 | 
				
			||||||
				// the top of the text or the bottom of the text to
 | 
					 | 
				
			||||||
				// the pressure line.
 | 
					 | 
				
			||||||
				double value_y_offset = -0.5;
 | 
					 | 
				
			||||||
				double label_y_offset = alignVar & Qt::AlignTop ? labelHeight : -labelHeight;
 | 
					 | 
				
			||||||
				plotPressureValue(mbar, entry->sec, alignVar, value_y_offset);
 | 
					 | 
				
			||||||
				plotGasValue(mbar, entry->sec, get_cylinder(d, cyl)->gasmix, alignVar, label_y_offset);
 | 
					 | 
				
			||||||
				seen_cyl[cyl] = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* Alternate alignment as we see cylinder use.. */
 | 
					 | 
				
			||||||
				align[cyl] = alignVar;
 | 
					 | 
				
			||||||
				alignVar ^= Qt::AlignTop | Qt::AlignBottom;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			last_pressure[cyl] = mbar;
 | 
					 | 
				
			||||||
			last_time[cyl] = entry->sec;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// For each cylinder, on right hand side of profile, write cylinder pressure
 | 
					 | 
				
			||||||
	for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
 | 
					 | 
				
			||||||
		if (last_time[cyl]) {
 | 
					 | 
				
			||||||
			double value_y_offset = -0.5;
 | 
					 | 
				
			||||||
			plotPressureValue(last_pressure[cyl], last_time[cyl], align[cyl] | Qt::AlignLeft, value_y_offset);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DiveGasPressureItem::plotPressureValue(int mbar, int sec, QFlags<Qt::AlignmentFlag> align, double pressure_offset)
 | 
					void DiveGasPressureItem::plotPressureValue(double mbar, double sec, QFlags<Qt::AlignmentFlag> align, double pressure_offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *unit;
 | 
						const char *unit;
 | 
				
			||||||
	int pressure = get_pressure_units(mbar, &unit);
 | 
						int pressure = get_pressure_units(lrint(mbar), &unit);
 | 
				
			||||||
	DiveTextItem *text = new DiveTextItem(dpr, 1.0, align, this);
 | 
						DiveTextItem *text = new DiveTextItem(dpr, 1.0, align, this);
 | 
				
			||||||
	text->set(QString("%1%2").arg(pressure).arg(unit), getColor(PRESSURE_TEXT));
 | 
						text->set(QString("%1%2").arg(pressure).arg(unit), getColor(PRESSURE_TEXT));
 | 
				
			||||||
	text->setPos(hAxis.posAtValue(sec), vAxis.posAtValue(mbar) + pressure_offset);
 | 
						text->setPos(hAxis.posAtValue(sec), vAxis.posAtValue(mbar) + pressure_offset);
 | 
				
			||||||
	texts.push_back(text);
 | 
						texts.push_back(text);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DiveGasPressureItem::plotGasValue(int mbar, int sec, struct gasmix gasmix, QFlags<Qt::AlignmentFlag> align, double gasname_offset)
 | 
					void DiveGasPressureItem::plotGasValue(double mbar, double sec, struct gasmix gasmix, QFlags<Qt::AlignmentFlag> align, double gasname_offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	QString gas = get_gas_string(gasmix);
 | 
						QString gas = get_gas_string(gasmix);
 | 
				
			||||||
	DiveTextItem *text = new DiveTextItem(dpr, 1.0, align, this);
 | 
						DiveTextItem *text = new DiveTextItem(dpr, 1.0, align, this);
 | 
				
			||||||
| 
						 | 
					@ -537,11 +607,11 @@ void DiveGasPressureItem::paint(QPainter *painter, const QStyleOptionGraphicsIte
 | 
				
			||||||
	pen.setCosmetic(true);
 | 
						pen.setCosmetic(true);
 | 
				
			||||||
	pen.setWidth(2);
 | 
						pen.setWidth(2);
 | 
				
			||||||
	painter->save();
 | 
						painter->save();
 | 
				
			||||||
	for (const std::vector<Entry> &poly: polygons) {
 | 
						for (const Segment &segment: segments) {
 | 
				
			||||||
		for (size_t i = 1; i < poly.size(); i++) {
 | 
							for (size_t i = 1; i < segment.polygon.size(); i++) {
 | 
				
			||||||
			pen.setBrush(poly[i].col);
 | 
								pen.setBrush(segment.polygon[i].col);
 | 
				
			||||||
			painter->setPen(pen);
 | 
								painter->setPen(pen);
 | 
				
			||||||
			painter->drawLine(poly[i - 1].pos, poly[i].pos);
 | 
								painter->drawLine(segment.polygon[i - 1].pos, segment.polygon[i].pos);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	painter->restore();
 | 
						painter->restore();
 | 
				
			||||||
| 
						 | 
					@ -583,6 +653,27 @@ DiveReportedCeiling::DiveReportedCeiling(const DivePlotDataModel &model, const D
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::pair<double,double> DiveReportedCeiling::getTimeValue(int i) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const plot_data &entry = dataModel.data().entry[i];
 | 
				
			||||||
 | 
						int value = entry.in_deco && entry.stopdepth ? std::min(entry.stopdepth, entry.depth) : 0;
 | 
				
			||||||
 | 
						return { static_cast<double>(entry.sec), static_cast<double>(value) };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::pair<double, double> DiveReportedCeiling::getPoint(int i) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						auto [x,y] = getTimeValue(i);
 | 
				
			||||||
 | 
						if (i == from && i < to) {
 | 
				
			||||||
 | 
							auto [next_x, next_y] = getTimeValue(i + 1);
 | 
				
			||||||
 | 
							clipStart(x, y, next_x, next_y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (i == to - 1 && i > 0) {
 | 
				
			||||||
 | 
							auto [prev_x, prev_y] = getTimeValue(i - 1);
 | 
				
			||||||
 | 
							clipStop(x, y, prev_x, prev_y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return { x, y };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DiveReportedCeiling::replot(const dive *, int fromIn, int toIn, bool)
 | 
					void DiveReportedCeiling::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	from = fromIn;
 | 
						from = fromIn;
 | 
				
			||||||
| 
						 | 
					@ -590,14 +681,12 @@ void DiveReportedCeiling::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QPolygonF p;
 | 
						QPolygonF p;
 | 
				
			||||||
	for (int i = from; i < to; i++) {
 | 
						for (int i = from; i < to; i++) {
 | 
				
			||||||
		const plot_data &entry = dataModel.data().entry[i];
 | 
							auto [sec, value] = getPoint(i);
 | 
				
			||||||
		if (i == from)
 | 
							if (i == from)
 | 
				
			||||||
			p.append(QPointF(hAxis.posAtValue(entry.sec), vAxis.posAtValue(0)));
 | 
								p.append(QPointF(hAxis.posAtValue(sec), vAxis.posAtValue(0.0)));
 | 
				
			||||||
		if (entry.in_deco && entry.stopdepth) {
 | 
							p.append(QPointF(hAxis.posAtValue(sec), vAxis.posAtValue(value)));
 | 
				
			||||||
			p.append(QPointF(hAxis.posAtValue(entry.sec), vAxis.posAtValue(std::min(entry.stopdepth, entry.depth))));
 | 
							if (i == to - 1)
 | 
				
			||||||
		} else {
 | 
								p.append(QPointF(hAxis.posAtValue(sec), vAxis.posAtValue(0)));
 | 
				
			||||||
			p.append(QPointF(hAxis.posAtValue(entry.sec), vAxis.posAtValue(0)));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setPolygon(p);
 | 
						setPolygon(p);
 | 
				
			||||||
	QLinearGradient pat(0, p.boundingRect().top(), 0, p.boundingRect().bottom());
 | 
						QLinearGradient pat(0, p.boundingRect().top(), 0, p.boundingRect().bottom());
 | 
				
			||||||
| 
						 | 
					@ -625,7 +714,6 @@ void PartialPressureGasItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
	from = fromIn;
 | 
						from = fromIn;
 | 
				
			||||||
	to = toIn;
 | 
						to = toIn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	plot_data *entry = dataModel.data().entry + from;
 | 
					 | 
				
			||||||
	QPolygonF poly;
 | 
						QPolygonF poly;
 | 
				
			||||||
	QPolygonF alertpoly;
 | 
						QPolygonF alertpoly;
 | 
				
			||||||
	alertPolygons.clear();
 | 
						alertPolygons.clear();
 | 
				
			||||||
| 
						 | 
					@ -636,9 +724,8 @@ void PartialPressureGasItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
	if (thresholdPtrMin)
 | 
						if (thresholdPtrMin)
 | 
				
			||||||
		threshold_min = *thresholdPtrMin;
 | 
							threshold_min = *thresholdPtrMin;
 | 
				
			||||||
	bool inAlertFragment = false;
 | 
						bool inAlertFragment = false;
 | 
				
			||||||
	for (int i = from; i < to; i++, entry++) {
 | 
						for (int i = from; i < to; i++) {
 | 
				
			||||||
		double value = dataModel.index(i, vDataColumn).data().toDouble();
 | 
							auto [time, value] = getPoint(i);
 | 
				
			||||||
		int time = dataModel.index(i, hDataColumn).data().toInt();
 | 
					 | 
				
			||||||
		QPointF point(hAxis.posAtValue(time), vAxis.posAtValue(value));
 | 
							QPointF point(hAxis.posAtValue(time), vAxis.posAtValue(value));
 | 
				
			||||||
		poly.push_back(point);
 | 
							poly.push_back(point);
 | 
				
			||||||
		if (thresholdPtrMax && value >= threshold_max) {
 | 
							if (thresholdPtrMax && value >= threshold_max) {
 | 
				
			||||||
| 
						 | 
					@ -664,9 +751,6 @@ void PartialPressureGasItem::replot(const dive *, int fromIn, int toIn, bool)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setPolygon(poly);
 | 
						setPolygon(poly);
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	createPPLegend(trUtf8("pN₂"), getColor(PN2), legendPos);
 | 
					 | 
				
			||||||
	*/
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PartialPressureGasItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*)
 | 
					void PartialPressureGasItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,9 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	void makePolygon(int from, int to);
 | 
						void makePolygon(int from, int to);
 | 
				
			||||||
 | 
						void clipStart(double &x, double &y, double next_x, double next_y) const;
 | 
				
			||||||
 | 
						void clipStop(double &x, double &y, double prev_x, double prev_y) const;
 | 
				
			||||||
 | 
						std::pair<double, double> getPoint(int i) const;
 | 
				
			||||||
	const DiveCartesianAxis &hAxis;
 | 
						const DiveCartesianAxis &hAxis;
 | 
				
			||||||
	const DiveCartesianAxis &vAxis;
 | 
						const DiveCartesianAxis &vAxis;
 | 
				
			||||||
	const DivePlotDataModel &dataModel;
 | 
						const DivePlotDataModel &dataModel;
 | 
				
			||||||
| 
						 | 
					@ -74,8 +77,9 @@ public:
 | 
				
			||||||
	void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
 | 
						void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void createTextItem();
 | 
						void createTextItem(double lastSec, double lastMeanDepth);
 | 
				
			||||||
	double lastRunningSum;
 | 
						std::pair<double,double> getMeanDepth(int i) const;
 | 
				
			||||||
 | 
						std::pair<double,double> getNextMeanDepth(int i) const;
 | 
				
			||||||
	QString visibilityKey;
 | 
						QString visibilityKey;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,13 +115,22 @@ public:
 | 
				
			||||||
	void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
 | 
						void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void plotPressureValue(int mbar, int sec, QFlags<Qt::AlignmentFlag> align, double offset);
 | 
						void plotPressureValue(double mbar, double sec, QFlags<Qt::AlignmentFlag> align, double offset);
 | 
				
			||||||
	void plotGasValue(int mbar, int sec, struct gasmix gasmix, QFlags<Qt::AlignmentFlag> align, double offset);
 | 
						void plotGasValue(double mbar, double sec, struct gasmix gasmix, QFlags<Qt::AlignmentFlag> align, double offset);
 | 
				
			||||||
 | 
						struct PressureEntry {
 | 
				
			||||||
 | 
							double time = 0.0;
 | 
				
			||||||
 | 
							double pressure = 0.0;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
	struct Entry {
 | 
						struct Entry {
 | 
				
			||||||
		QPointF pos;
 | 
							QPointF pos;
 | 
				
			||||||
		QColor col;
 | 
							QColor col;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	std::vector<std::vector<Entry>> polygons;
 | 
						struct Segment {
 | 
				
			||||||
 | 
							int cyl;
 | 
				
			||||||
 | 
							std::vector<Entry> polygon;
 | 
				
			||||||
 | 
							PressureEntry first, last;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						std::vector<Segment> segments;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DiveCalculatedCeiling : public AbstractProfilePolygonItem {
 | 
					class DiveCalculatedCeiling : public AbstractProfilePolygonItem {
 | 
				
			||||||
| 
						 | 
					@ -137,6 +150,9 @@ public:
 | 
				
			||||||
	DiveReportedCeiling(const DivePlotDataModel &model, const DiveCartesianAxis &hAxis, int hColumn, const DiveCartesianAxis &vAxis, int vColumn, double dpr);
 | 
						DiveReportedCeiling(const DivePlotDataModel &model, const DiveCartesianAxis &hAxis, int hColumn, const DiveCartesianAxis &vAxis, int vColumn, double dpr);
 | 
				
			||||||
	void replot(const dive *d, int from, int to, bool in_planner) override;
 | 
						void replot(const dive *d, int from, int to, bool in_planner) override;
 | 
				
			||||||
	void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
 | 
						void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						std::pair<double,double> getTimeValue(int i) const;
 | 
				
			||||||
 | 
						std::pair<double, double> getPoint(int i) const;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DiveCalculatedTissue : public DiveCalculatedCeiling {
 | 
					class DiveCalculatedTissue : public DiveCalculatedCeiling {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue