mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	For CCR dives, show plot for diluent and O2 cylinder pressures
Also fixes a bug in the diluent pressure interpolation Signed-off-by: Robert C. Helling <helling@atdotde.de> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
		
							parent
							
								
									992e58eaf2
								
							
						
					
					
						commit
						d5d7fdc9af
					
				
					 6 changed files with 67 additions and 24 deletions
				
			
		
							
								
								
									
										2
									
								
								TODO.CCR
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								TODO.CCR
									
										
									
									
									
								
							|  | @ -1,5 +1,5 @@ | ||||||
| TODO for CCR support | TODO for CCR support | ||||||
| 
 | 
 | ||||||
| - tank pressure plot (see test40.xml) | - make tank pressure plot work for bailout dives | ||||||
| - bailout handling in SAC rate calculation | - bailout handling in SAC rate calculation | ||||||
| - UI to modify the tank type for CCR (i.e., set the diluent and oxygen cylinders) | - UI to modify the tank type for CCR (i.e., set the diluent and oxygen cylinders) | ||||||
|  |  | ||||||
|  | @ -99,6 +99,8 @@ static void dump_pr_track(pr_track_t **track_pr) | ||||||
|  */ |  */ | ||||||
| static void fill_missing_segment_pressures(pr_track_t *list, enum interpolation_strategy strategy) | static void fill_missing_segment_pressures(pr_track_t *list, enum interpolation_strategy strategy) | ||||||
| { | { | ||||||
|  | 	double magic; | ||||||
|  | 
 | ||||||
| 	while (list) { | 	while (list) { | ||||||
| 		int start = list->start, end; | 		int start = list->start, end; | ||||||
| 		pr_track_t *tmp = list; | 		pr_track_t *tmp = list; | ||||||
|  | @ -144,10 +146,12 @@ static void fill_missing_segment_pressures(pr_track_t *list, enum interpolation_ | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| 		case TIME: | 		case TIME: | ||||||
| 			if (list->t_end && (tmp->t_start - tmp->t_end)) | 			if (list->t_end && (tmp->t_start - tmp->t_end)) { | ||||||
| 				list->end = start - (start - end) * (list->t_end - tmp->t_end) / (tmp->t_start - tmp->t_end); | 				magic = (list->t_start - tmp->t_end) / (tmp->t_start - tmp->t_end); | ||||||
| 			else | 				list->end = rint(start - (start - end) * magic); | ||||||
|  | 			} else { | ||||||
| 				list->end = start; | 				list->end = start; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		case CONSTANT: | 		case CONSTANT: | ||||||
| 			list->end = start; | 			list->end = start; | ||||||
|  | @ -219,7 +223,7 @@ static struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t *segment, | ||||||
| 	return interpolate; | 	return interpolate; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr, int o2_flag) | static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr, bool o2_flag) | ||||||
| { | { | ||||||
| 	int cyl, i; | 	int cyl, i; | ||||||
| 	struct plot_data *entry; | 	struct plot_data *entry; | ||||||
|  | @ -291,16 +295,22 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, | ||||||
| 			*save_pressure = cur_pr[cyl];      // Just use our current pressure
 | 			*save_pressure = cur_pr[cyl];      // Just use our current pressure
 | ||||||
| 			continue;			   // and skip to next point.
 | 			continue;			   // and skip to next point.
 | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		// If there is a valid segment but no tank pressure ..
 | 		// If there is a valid segment but no tank pressure ..
 | ||||||
| 		interpolate = get_pr_interpolate_data(segment, pi, i, pressure); // Set up an interpolation structure
 | 		interpolate = get_pr_interpolate_data(segment, pi, i, pressure); // Set up an interpolation structure
 | ||||||
|  | 		if(dive->cylinder[cyl].cylinder_use == OC_GAS) { | ||||||
| 
 | 
 | ||||||
| 		/* if this segment has pressure_time, then calculate a new interpolated pressure */ | 			/* if this segment has pressure_time, then calculate a new interpolated pressure */ | ||||||
| 		if (interpolate.pressure_time) { | 			if (interpolate.pressure_time) { | ||||||
| 			/* Overall pressure change over total pressure-time for this segment*/ | 				/* Overall pressure change over total pressure-time for this segment*/ | ||||||
| 			magic = (interpolate.end - interpolate.start) / (double)interpolate.pressure_time; | 				magic = (interpolate.end - interpolate.start) / (double)interpolate.pressure_time; | ||||||
| 
 | 
 | ||||||
| 			/* Use that overall pressure change to update the current pressure */ | 				/* Use that overall pressure change to update the current pressure */ | ||||||
| 			cur_pr[cyl] = rint(interpolate.start + magic * interpolate.acc_pressure_time); | 				cur_pr[cyl] = rint(interpolate.start + magic * interpolate.acc_pressure_time); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			magic = (interpolate.end - interpolate.start) /  (segment->t_end - segment->t_start); | ||||||
|  | 			cur_pr[cyl] = rint(segment->start + magic * (entry->sec - segment->t_start)); | ||||||
| 		} | 		} | ||||||
| 		*save_interpolated = cur_pr[cyl]; // and store the interpolated data in plot_info
 | 		*save_interpolated = cur_pr[cyl]; // and store the interpolated data in plot_info
 | ||||||
| 	} | 	} | ||||||
|  | @ -341,7 +351,7 @@ static void debug_print_pressures(struct plot_info *pi) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* This function goes through the list of tank pressures, either SENSOR_PRESSURE(entry) or DILUENT_PRESSURE(entry),
 | /* This function goes through the list of tank pressures, either SENSOR_PRESSURE(entry) or O2CYLINDER_PRESSURE(entry),
 | ||||||
|  * of structure plot_info for the dive profile where each item in the list corresponds to one point (node) of the |  * of structure plot_info for the dive profile where each item in the list corresponds to one point (node) of the | ||||||
|  * profile. It finds values for which there are no tank pressures (pressure==0). For each missing item (node) of |  * profile. It finds values for which there are no tank pressures (pressure==0). For each missing item (node) of | ||||||
|  * tank pressure it creates a pr_track_alloc structure that represents a segment on the dive profile and that |  * tank pressure it creates a pr_track_alloc structure that represents a segment on the dive profile and that | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								profile.c
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								profile.c
									
										
									
									
									
								
							|  | @ -612,34 +612,40 @@ struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer * | ||||||
| 
 | 
 | ||||||
| #undef INSERT_ENTRY | #undef INSERT_ENTRY | ||||||
| 
 | 
 | ||||||
| static void populate_cylinder_pressure_data(int idx, int start, int end, struct plot_info *pi) | static void populate_cylinder_pressure_data(int idx, int start, int end, struct plot_info *pi, bool o2flag) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	/* First: check that none of the entries has sensor pressure for this cylinder index */ | 	/* First: check that none of the entries has sensor pressure for this cylinder index */ | ||||||
| 	for (i = 0; i < pi->nr; i++) { | 	for (i = 0; i < pi->nr; i++) { | ||||||
| 		struct plot_data *entry = pi->entry + i; | 		struct plot_data *entry = pi->entry + i; | ||||||
| 		if (entry->cylinderindex != idx) | 		if (entry->cylinderindex != idx && !o2flag) | ||||||
| 			continue; | 			continue; | ||||||
| 		if (SENSOR_PRESSURE(entry)) | 		if (CYLINDER_PRESSURE(o2flag, entry)) | ||||||
| 			return; | 			return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Then: populate the first entry with the beginning cylinder pressure */ | 	/* Then: populate the first entry with the beginning cylinder pressure */ | ||||||
| 	for (i = 0; i < pi->nr; i++) { | 	for (i = 0; i < pi->nr; i++) { | ||||||
| 		struct plot_data *entry = pi->entry + i; | 		struct plot_data *entry = pi->entry + i; | ||||||
| 		if (entry->cylinderindex != idx) | 		if (entry->cylinderindex != idx && !o2flag) | ||||||
| 			continue; | 			continue; | ||||||
| 		SENSOR_PRESSURE(entry) = start; | 		if (o2flag) | ||||||
|  | 			O2CYLINDER_PRESSURE(entry) = start; | ||||||
|  | 		else | ||||||
|  | 			SENSOR_PRESSURE(entry) = start; | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* .. and the last entry with the ending cylinder pressure */ | 	/* .. and the last entry with the ending cylinder pressure */ | ||||||
| 	for (i = pi->nr; --i >= 0; /* nothing */) { | 	for (i = pi->nr; --i >= 0; /* nothing */) { | ||||||
| 		struct plot_data *entry = pi->entry + i; | 		struct plot_data *entry = pi->entry + i; | ||||||
| 		if (entry->cylinderindex != idx) | 		if (entry->cylinderindex != idx && !o2flag) | ||||||
| 			continue; | 			continue; | ||||||
| 		SENSOR_PRESSURE(entry) = end; | 		if (o2flag) | ||||||
|  | 			O2CYLINDER_PRESSURE(entry) = end; | ||||||
|  | 		else | ||||||
|  | 			SENSOR_PRESSURE(entry) = end; | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -688,7 +694,7 @@ static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc | ||||||
| 		if (!start || !end) | 		if (!start || !end) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		populate_cylinder_pressure_data(i, start, end, pi); | 		populate_cylinder_pressure_data(i, start, end, pi, dive->cylinder[i].cylinder_use == OXYGEN); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -1013,9 +1019,9 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo | ||||||
| 
 | 
 | ||||||
| 	check_gas_change_events(dive, dc, pi);			/* Populate the gas index from the gas change events */ | 	check_gas_change_events(dive, dc, pi);			/* Populate the gas index from the gas change events */ | ||||||
| 	setup_gas_sensor_pressure(dive, dc, pi);		/* Try to populate our gas pressure knowledge */ | 	setup_gas_sensor_pressure(dive, dc, pi);		/* Try to populate our gas pressure knowledge */ | ||||||
| 	populate_pressure_information(dive, dc, pi, false);	/* .. calculate missing pressure entries for all gasses except diluent */ | 	populate_pressure_information(dive, dc, pi, false);	/* .. calculate missing pressure entries for all gasses except o2 */ | ||||||
| 	if (dc->dctype == CCR)					/* For CCR dives.. */ | 	if (dc->dctype == CCR)					/* For CCR dives.. */ | ||||||
| 		populate_pressure_information(dive, dc, pi, true); /* .. calculate missing diluent gas pressure entries */ | 		populate_pressure_information(dive, dc, pi, true); /* .. calculate missing o2 gas pressure entries */ | ||||||
| 
 | 
 | ||||||
| 	fill_o2_values(dc, pi, dive);				/* .. and insert the O2 sensor data having 0 values. */ | 	fill_o2_values(dc, pi, dive);				/* .. and insert the O2 sensor data having 0 values. */ | ||||||
| 	calculate_sac(dive, pi); /* Calculate sac */ | 	calculate_sac(dive, pi); /* Calculate sac */ | ||||||
|  |  | ||||||
|  | @ -92,9 +92,11 @@ int get_maxdepth(struct plot_info *pi); | ||||||
| #define INTERPOLATED_PR 1 | #define INTERPOLATED_PR 1 | ||||||
| #define SENSOR_PRESSURE(_entry) (_entry)->pressure[SENSOR_PR] | #define SENSOR_PRESSURE(_entry) (_entry)->pressure[SENSOR_PR] | ||||||
| #define O2CYLINDER_PRESSURE(_entry) (_entry)->o2cylinderpressure[SENSOR_PR] | #define O2CYLINDER_PRESSURE(_entry) (_entry)->o2cylinderpressure[SENSOR_PR] | ||||||
|  | #define CYLINDER_PRESSURE(_o2, _entry) (_o2 ? O2CYLINDER_PRESSURE(_entry) : SENSOR_PRESSURE(_entry)) | ||||||
| #define INTERPOLATED_PRESSURE(_entry) (_entry)->pressure[INTERPOLATED_PR] | #define INTERPOLATED_PRESSURE(_entry) (_entry)->pressure[INTERPOLATED_PR] | ||||||
| #define INTERPOLATED_O2CYLINDER_PRESSURE(_entry) (_entry)->o2cylinderpressure[INTERPOLATED_PR] | #define INTERPOLATED_O2CYLINDER_PRESSURE(_entry) (_entry)->o2cylinderpressure[INTERPOLATED_PR] | ||||||
| #define GET_PRESSURE(_entry) (SENSOR_PRESSURE(_entry) ? SENSOR_PRESSURE(_entry) : INTERPOLATED_PRESSURE(_entry)) | #define GET_PRESSURE(_entry) (SENSOR_PRESSURE(_entry) ? SENSOR_PRESSURE(_entry) : INTERPOLATED_PRESSURE(_entry)) | ||||||
|  | #define GET_O2CYLINDER_PRESSURE(_entry) (O2CYLINDER_PRESSURE(_entry) ? O2CYLINDER_PRESSURE(_entry) : INTERPOLATED_O2CYLINDER_PRESSURE(_entry)) | ||||||
| #define SAC_WINDOW 45 /* sliding window in seconds for current SAC calculation */ | #define SAC_WINDOW 45 /* sliding window in seconds for current SAC calculation */ | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  |  | ||||||
|  | @ -36,7 +36,7 @@ | ||||||
| QString gasToStr(struct gasmix gas) | QString gasToStr(struct gasmix gas) | ||||||
| { | { | ||||||
| 	uint o2 = (get_o2(&gas) + 5) / 10, he = (get_he(&gas) + 5) / 10; | 	uint o2 = (get_o2(&gas) + 5) / 10, he = (get_he(&gas) + 5) / 10; | ||||||
| 	QString result = gasmix_is_air(&gas) ? QObject::tr("AIR") : he == 0 ? QString("EAN%1").arg(o2, 2, 10, QChar('0')) : QString("%1/%2").arg(o2).arg(he); | 	QString result = gasmix_is_air(&gas) ? QObject::tr("AIR") : he == 0 ? (o2 == 100 ? QObject::tr("OXYGEN") : QString("EAN%1").arg(o2, 2, 10, QChar('0'))) : QString("%1/%2").arg(o2).arg(he); | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -574,12 +574,18 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo | ||||||
| 	if (!shouldCalculateStuff(topLeft, bottomRight)) | 	if (!shouldCalculateStuff(topLeft, bottomRight)) | ||||||
| 		return; | 		return; | ||||||
| 	int last_index = -1; | 	int last_index = -1; | ||||||
| 	QPolygonF boundingPoly; // This is the "Whole Item", but a pressure can be divided in N Polygons.
 | 	int o2mbar; | ||||||
|  | 	QPolygonF boundingPoly, o2Poly; // This is the "Whole Item", but a pressure can be divided in N Polygons.
 | ||||||
| 	polygons.clear(); | 	polygons.clear(); | ||||||
|  | 	if (displayed_dive.dc.dctype == CCR) | ||||||
|  | 		polygons.append(o2Poly); | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0, count = dataModel->rowCount(); i < count; i++) { | 	for (int i = 0, count = dataModel->rowCount(); i < count; i++) { | ||||||
|  | 		o2mbar = 0; | ||||||
| 		plot_data *entry = dataModel->data().entry + i; | 		plot_data *entry = dataModel->data().entry + i; | ||||||
| 		int mbar = GET_PRESSURE(entry); | 		int mbar = GET_PRESSURE(entry); | ||||||
|  | 		if (displayed_dive.dc.dctype == CCR) | ||||||
|  | 			o2mbar = GET_O2CYLINDER_PRESSURE(entry); | ||||||
| 
 | 
 | ||||||
| 		if (entry->cylinderindex != last_index) { | 		if (entry->cylinderindex != last_index) { | ||||||
| 			polygons.append(QPolygonF()); // this is the polygon that will be actually drawned on screen.
 | 			polygons.append(QPolygonF()); // this is the polygon that will be actually drawned on screen.
 | ||||||
|  | @ -588,6 +594,11 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo | ||||||
| 		if (!mbar) { | 		if (!mbar) { | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  | 		if (o2mbar) { | ||||||
|  | 			QPointF o2point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(o2mbar)); | ||||||
|  | 			boundingPoly.push_back(o2point); | ||||||
|  | 			polygons.first().push_back(o2point); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		QPointF point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(mbar)); | 		QPointF point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(mbar)); | ||||||
| 		boundingPoly.push_back(point);    // The BoundingRect
 | 		boundingPoly.push_back(point);    // The BoundingRect
 | ||||||
|  | @ -603,9 +614,23 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo | ||||||
| 	struct plot_data *entry; | 	struct plot_data *entry; | ||||||
| 
 | 
 | ||||||
| 	cyl = -1; | 	cyl = -1; | ||||||
|  | 	o2mbar = 0; | ||||||
| 	for (int i = 0, count = dataModel->rowCount(); i < count; i++) { | 	for (int i = 0, count = dataModel->rowCount(); i < count; i++) { | ||||||
| 		entry = dataModel->data().entry + i; | 		entry = dataModel->data().entry + i; | ||||||
| 		mbar = GET_PRESSURE(entry); | 		mbar = GET_PRESSURE(entry); | ||||||
|  | 		if (displayed_dive.dc.dctype == CCR) | ||||||
|  | 			o2mbar = GET_O2CYLINDER_PRESSURE(entry); | ||||||
|  | 
 | ||||||
|  | 		if (o2mbar) { | ||||||
|  | 			if (!seen_cyl[displayed_dive.oxygen_cylinder_index]) { | ||||||
|  | 				plotPressureValue(o2mbar, entry->sec, Qt::AlignRight | Qt::AlignBottom); | ||||||
|  | 				plotGasValue(o2mbar, entry->sec, Qt::AlignRight | Qt::AlignBottom, displayed_dive.cylinder[displayed_dive.oxygen_cylinder_index].gasmix); | ||||||
|  | 				seen_cyl[displayed_dive.oxygen_cylinder_index] = true; | ||||||
|  | 			} | ||||||
|  | 			last_pressure[displayed_dive.oxygen_cylinder_index] = o2mbar; | ||||||
|  | 			last_time[displayed_dive.oxygen_cylinder_index] = entry->sec; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 		if (!mbar) | 		if (!mbar) | ||||||
| 			continue; | 			continue; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue