Ejemplo n.º 1
0
/*
 * Calculate the sac rate between the two plot entries 'first' and 'last'.
 *
 * Everything in between has a cylinder pressure, and it's all the same
 * cylinder.
 */
static int sac_between(struct dive *dive, struct plot_data *first, struct plot_data *last)
{
	int airuse;
	double pressuretime;
	pressure_t a, b;
	cylinder_t *cyl;

	if (first == last)
		return 0;

	/* Calculate air use - trivial */
	a.mbar = GET_PRESSURE(first);
	b.mbar = GET_PRESSURE(last);
	cyl = dive->cylinder + first->cylinderindex;
	airuse = gas_volume(cyl, a) - gas_volume(cyl, b);
	if (airuse <= 0)
		return 0;

	/* Calculate depthpressure integrated over time */
	pressuretime = 0.0;
	do {
		int depth = (first[0].depth + first[1].depth) / 2;
		int time = first[1].sec - first[0].sec;
		double atm = depth_to_atm(depth, dive);

		pressuretime += atm * time;
	} while (++first < last);

	/* Turn "atmseconds" into "atmminutes" */
	pressuretime /= 60;

	/* SAC = mliter per minute */
	return rint(airuse / pressuretime);
}
Ejemplo n.º 2
0
void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
	// We don't have enougth data to calculate things, quit.
	if (!shouldCalculateStuff(topLeft, bottomRight))
		return;
	int last_index = -1;
	QPolygonF boundingPoly; // This is the "Whole Item", but a pressure can be divided in N Polygons.
	polygons.clear();

	for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
		plot_data *entry = dataModel->data().entry + i;
		int mbar = GET_PRESSURE(entry);

		if (entry->cylinderindex != last_index) {
			polygons.append(QPolygonF()); // this is the polygon that will be actually drawned on screen.
			last_index = entry->cylinderindex;
		}
		if (!mbar) {
			continue;
		}

		QPointF point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(mbar));
		boundingPoly.push_back(point);    // The BoundingRect
		polygons.last().push_back(point); // The polygon thta will be plotted.
	}
	setPolygon(boundingPoly);
	qDeleteAll(texts);
	texts.clear();
	int mbar, cyl;
	int seen_cyl[MAX_CYLINDERS] = { false, };
	int last_pressure[MAX_CYLINDERS] = { 0, };
	int last_time[MAX_CYLINDERS] = { 0, };
	struct plot_data *entry;

	cyl = -1;
	for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
		entry = dataModel->data().entry + i;
		mbar = GET_PRESSURE(entry);

		if (!mbar)
			continue;
		if (cyl != entry->cylinderindex) {
			cyl = entry->cylinderindex;
			if (!seen_cyl[cyl]) {
				plotPressureValue(mbar, entry->sec, Qt::AlignRight | Qt::AlignTop);
				plotGasValue(mbar, entry->sec, Qt::AlignRight | Qt::AlignBottom,
					       displayed_dive.cylinder[cyl].gasmix);
				seen_cyl[cyl] = true;
			}
		}
		last_pressure[cyl] = mbar;
		last_time[cyl] = entry->sec;
	}

	for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
		if (last_time[cyl]) {
			plotPressureValue(last_pressure[cyl], last_time[cyl], Qt::AlignLeft | Qt::AlignTop);
		}
	}
}
Ejemplo n.º 3
0
/* Get local sac-rate (in ml/min) between entry1 and entry2 */
static int get_local_sac(struct plot_data *entry1, struct plot_data *entry2, struct dive *dive)
{
	int index = entry1->cylinderindex;
	cylinder_t *cyl;
	int duration = entry2->sec - entry1->sec;
	int depth, airuse;
	pressure_t a, b;
	double atm;

	if (entry2->cylinderindex != index)
		return 0;
	if (duration <= 0)
		return 0;
	a.mbar = GET_PRESSURE(entry1);
	b.mbar = GET_PRESSURE(entry2);
	if (!b.mbar || a.mbar <= b.mbar)
		return 0;

	/* Mean pressure in ATM */
	depth = (entry1->depth + entry2->depth) / 2;
	atm = depth_to_atm(depth, dive);

	cyl = dive->cylinder + index;

	airuse = gas_volume(cyl, a) - gas_volume(cyl, b);

	/* milliliters per minute */
	return airuse / atm * 60 / duration;
}
Ejemplo n.º 4
0
void ProfileGraphicsView::plot_cylinder_pressure()
{
    int i;
    int last_index = -1;
    int lift_pen = FALSE;
    int first_plot = TRUE;

    if (!get_cylinder_pressure_range(&gc))
        return;

    QPointF from, to;
    for (i = 0; i < gc.pi.nr; i++) {
        int mbar;
        struct plot_data *entry = gc.pi.entry + i;

        mbar = GET_PRESSURE(entry);
        if (entry->cylinderindex != last_index) {
            lift_pen = TRUE;
        }
        if (!mbar) {
            lift_pen = TRUE;
            continue;
        }

        QColor c = get_sac_color(entry->sac, dive->sac);

        if (lift_pen) {
            if (!first_plot && entry->cylinderindex == last_index) {
                /* if we have a previous event from the same tank,
                 * draw at least a short line */
                int prev_pr;
                prev_pr = GET_PRESSURE(entry - 1);

                QGraphicsLineItem *item = new QGraphicsLineItem(SCALEGC((entry-1)->sec, prev_pr), SCALEGC(entry->sec, mbar));
                QPen pen(defaultPen);
                pen.setColor(c);
                item->setPen(pen);
                scene()->addItem(item);
            } else {
                first_plot = FALSE;
                from = QPointF(SCALEGC(entry->sec, mbar));
            }
            lift_pen = FALSE;
        } else {
            to = QPointF(SCALEGC(entry->sec, mbar));
            QGraphicsLineItem *item = new QGraphicsLineItem(from.x(), from.y(), to.x(), to.y());
            QPen pen(defaultPen);
            pen.setColor(c);
            item->setPen(pen);
            scene()->addItem(item);
        }

        from = QPointF(SCALEGC(entry->sec, mbar));
        last_index = entry->cylinderindex;
    }
}
Ejemplo n.º 5
0
/*
 * Try to do the momentary sac rate for this entry, averaging over one
 * minute.
 */
static void fill_sac(struct dive *dive, struct plot_info *pi, int idx)
{
	struct plot_data *entry = pi->entry + idx;
	struct plot_data *first, *last;
	int time;

	if (entry->sac)
		return;

	if (!GET_PRESSURE(entry))
		return;

	/*
	 * Try to go back 30 seconds to get 'first'.
	 * Stop if the sensor changed, or if we went back too far.
	 */
	first = entry;
	time = entry->sec - 30;
	while (idx > 0) {
		struct plot_data *prev = first-1;
		if (prev->cylinderindex != first->cylinderindex)
			break;
		if (prev->depth < SURFACE_THRESHOLD && first->depth < SURFACE_THRESHOLD)
			break;
		if (prev->sec < time)
			break;
		if (!GET_PRESSURE(prev))
			break;
		idx--;
		first = prev;
	}

	/* Now find an entry a minute after the first one */
	last = first;
	time = first->sec + 60;
	while (++idx < pi->nr) {
		struct plot_data *next = last+1;
		if (next->cylinderindex != last->cylinderindex)
			break;
		if (next->depth < SURFACE_THRESHOLD && last->depth < SURFACE_THRESHOLD)
			break;
		if (next->sec > time)
			break;
		if (!GET_PRESSURE(next))
			break;
		last = next;
	}

	/* Ok, now calculate the SAC between 'first' and 'last' */
	entry->sac = sac_between(dive, first, last);
}
Ejemplo n.º 6
0
void ProfileGraphicsView::plot_cylinder_pressure_text()
{
    int i;
    int mbar, cyl;
    int seen_cyl[MAX_CYLINDERS] = { FALSE, };
    int last_pressure[MAX_CYLINDERS] = { 0, };
    int last_time[MAX_CYLINDERS] = { 0, };
    struct plot_data *entry;
    struct plot_info *pi = &gc.pi;

    if (!get_cylinder_pressure_range(&gc))
        return;

    cyl = -1;
    for (i = 0; i < pi->nr; i++) {
        entry = pi->entry + i;
        mbar = GET_PRESSURE(entry);

        if (!mbar)
            continue;
        if (cyl != entry->cylinderindex) {
            cyl = entry->cylinderindex;
            if (!seen_cyl[cyl]) {
                plot_pressure_value(mbar, entry->sec, LEFT, BOTTOM);
                plot_gas_value(mbar, entry->sec, LEFT, TOP,
                               get_o2(&dive->cylinder[cyl].gasmix),
                               get_he(&dive->cylinder[cyl].gasmix));
                seen_cyl[cyl] = TRUE;
            }
        }
        last_pressure[cyl] = mbar;
        last_time[cyl] = entry->sec;
    }

    for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
        if (last_time[cyl]) {
            plot_pressure_value(last_pressure[cyl], last_time[cyl], CENTER, TOP);
        }
    }
}
Ejemplo n.º 7
0
/* Compare two plot_data entries and writes the results into a string */
void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int bufsize, int sum)
{
	struct plot_data *start, *stop, *data;
	const char *depth_unit, *pressure_unit, *vertical_speed_unit;
	char *buf2 = malloc(bufsize);
	int avg_speed, max_asc_speed, max_desc_speed;
	int delta_depth, avg_depth, max_depth, min_depth;
	int bar_used, last_pressure, pressurevalue;
	int count, last_sec, delta_time;

	double depthvalue, speedvalue;

	if (bufsize > 0)
		buf[0] = '\0';
	if (e1 == NULL || e2 == NULL) {
		free(buf2);
		return;
	}

	if (e1->sec < e2->sec) {
		start = e1;
		stop = e2;
	} else if (e1->sec > e2->sec) {
		start = e2;
		stop = e1;
	} else {
		free(buf2);
		return;
	}
	count = 0;
	avg_speed = 0;
	max_asc_speed = 0;
	max_desc_speed = 0;

	delta_depth = abs(start->depth - stop->depth);
	delta_time = abs(start->sec - stop->sec);
	avg_depth = 0;
	max_depth = 0;
	min_depth = INT_MAX;
	bar_used = 0;

	last_sec = start->sec;
	last_pressure = GET_PRESSURE(start);

	data = start;
	while (data != stop) {
		data = start + count;
		if (sum)
			avg_speed += abs(data->speed) * (data->sec - last_sec);
		else
			avg_speed += data->speed * (data->sec - last_sec);
		avg_depth += data->depth * (data->sec - last_sec);

		if (data->speed > max_desc_speed)
			max_desc_speed = data->speed;
		if (data->speed < max_asc_speed)
			max_asc_speed = data->speed;

		if (data->depth < min_depth)
			min_depth = data->depth;
		if (data->depth > max_depth)
			max_depth = data->depth;
		/* Try to detect gas changes */
		if (GET_PRESSURE(data) < last_pressure + 2000)
			bar_used += last_pressure - GET_PRESSURE(data);

		count += 1;
		last_sec = data->sec;
		last_pressure = GET_PRESSURE(data);
	}
	avg_depth /= stop->sec - start->sec;
	avg_speed /= stop->sec - start->sec;

	snprintf(buf, bufsize, translate("gettextFromC", "%sT: %d:%02d min"), UTF8_DELTA, delta_time / 60, delta_time % 60);
	memcpy(buf2, buf, bufsize);

	depthvalue = get_depth_units(delta_depth, NULL, &depth_unit);
	snprintf(buf, bufsize, translate("gettextFromC", "%s %sD:%.1f%s"), buf2, UTF8_DELTA, depthvalue, depth_unit);
	memcpy(buf2, buf, bufsize);

	depthvalue = get_depth_units(min_depth, NULL, &depth_unit);
	snprintf(buf, bufsize, translate("gettextFromC", "%s %sD:%.1f%s"), buf2, UTF8_DOWNWARDS_ARROW, depthvalue, depth_unit);
	memcpy(buf2, buf, bufsize);

	depthvalue = get_depth_units(max_depth, NULL, &depth_unit);
	snprintf(buf, bufsize, translate("gettextFromC", "%s %sD:%.1f%s"), buf2, UTF8_UPWARDS_ARROW, depthvalue, depth_unit);
	memcpy(buf2, buf, bufsize);

	depthvalue = get_depth_units(avg_depth, NULL, &depth_unit);
	snprintf(buf, bufsize, translate("gettextFromC", "%s %sD:%.1f%s\n"), buf2, UTF8_AVERAGE, depthvalue, depth_unit);
	memcpy(buf2, buf, bufsize);

	speedvalue = get_vertical_speed_units(abs(max_desc_speed), NULL, &vertical_speed_unit);
	snprintf(buf, bufsize, translate("gettextFromC", "%s%sV:%.2f%s"), buf2, UTF8_DOWNWARDS_ARROW, speedvalue, vertical_speed_unit);
	memcpy(buf2, buf, bufsize);

	speedvalue = get_vertical_speed_units(abs(max_asc_speed), NULL, &vertical_speed_unit);
	snprintf(buf, bufsize, translate("gettextFromC", "%s %sV:%.2f%s"), buf2, UTF8_UPWARDS_ARROW, speedvalue, vertical_speed_unit);
	memcpy(buf2, buf, bufsize);

	speedvalue = get_vertical_speed_units(abs(avg_speed), NULL, &vertical_speed_unit);
	snprintf(buf, bufsize, translate("gettextFromC", "%s %sV:%.2f%s"), buf2, UTF8_AVERAGE, speedvalue, vertical_speed_unit);
	memcpy(buf2, buf, bufsize);

	/* Only print if gas has been used */
	if (bar_used) {
		pressurevalue = get_pressure_units(bar_used, &pressure_unit);
		memcpy(buf2, buf, bufsize);
		snprintf(buf, bufsize, translate("gettextFromC", "%s %sP:%d %s"), buf2, UTF8_DELTA, pressurevalue, pressure_unit);
	}

	free(buf2);
}
Ejemplo n.º 8
0
static void plot_string(struct plot_info *pi, struct plot_data *entry, struct membuffer *b, bool has_ndl)
{
	int pressurevalue, mod, ead, end, eadd;
	const char *depth_unit, *pressure_unit, *temp_unit, *vertical_speed_unit;
	double depthvalue, tempvalue, speedvalue, sacvalue;
	int decimals;
	const char *unit;

	depthvalue = get_depth_units(entry->depth, NULL, &depth_unit);
	put_format(b, translate("gettextFromC", "@: %d:%02d\nD: %.1f%s\n"), FRACTION(entry->sec, 60), depthvalue, depth_unit);
	if (GET_PRESSURE(entry)) {
		pressurevalue = get_pressure_units(GET_PRESSURE(entry), &pressure_unit);
		put_format(b, translate("gettextFromC", "P: %d%s\n"), pressurevalue, pressure_unit);
	}
	if (entry->temperature) {
		tempvalue = get_temp_units(entry->temperature, &temp_unit);
		put_format(b, translate("gettextFromC", "T: %.1f%s\n"), tempvalue, temp_unit);
	}
	speedvalue = get_vertical_speed_units(abs(entry->speed), NULL, &vertical_speed_unit);
	/* Ascending speeds are positive, descending are negative */
	if (entry->speed > 0)
		speedvalue *= -1;
	put_format(b, translate("gettextFromC", "V: %.1f%s\n"), speedvalue, vertical_speed_unit);
	sacvalue = get_volume_units(entry->sac, &decimals, &unit);
	if (entry->sac && prefs.show_sac)
		put_format(b, translate("gettextFromC", "SAC: %.*f%s/min\n"), decimals, sacvalue, unit);
	if (entry->cns)
		put_format(b, translate("gettextFromC", "CNS: %u%%\n"), entry->cns);
	if (prefs.pp_graphs.po2)
		put_format(b, translate("gettextFromC", "pO%s: %.2fbar\n"), UTF8_SUBSCRIPT_2, entry->pressures.o2);
	if (prefs.pp_graphs.pn2)
		put_format(b, translate("gettextFromC", "pN%s: %.2fbar\n"), UTF8_SUBSCRIPT_2, entry->pressures.n2);
	if (prefs.pp_graphs.phe)
		put_format(b, translate("gettextFromC", "pHe: %.2fbar\n"), entry->pressures.he);
	if (prefs.mod) {
		mod = (int)get_depth_units(entry->mod, NULL, &depth_unit);
		put_format(b, translate("gettextFromC", "MOD: %d%s\n"), mod, depth_unit);
	}
	eadd = (int)get_depth_units(entry->eadd, NULL, &depth_unit);
	if (prefs.ead) {
		switch (pi->dive_type) {
		case NITROX:
			ead = (int)get_depth_units(entry->ead, NULL, &depth_unit);
			put_format(b, translate("gettextFromC", "EAD: %d%s\nEADD: %d%s\n"), ead, depth_unit, eadd, depth_unit);
			break;
		case TRIMIX:
			end = (int)get_depth_units(entry->end, NULL, &depth_unit);
			put_format(b, translate("gettextFromC", "END: %d%s\nEADD: %d%s\n"), end, depth_unit, eadd, depth_unit);
			break;
		case AIR:
		case FREEDIVING:
			/* nothing */
			break;
		}
	}
	if (entry->stopdepth) {
		depthvalue = get_depth_units(entry->stopdepth, NULL, &depth_unit);
		if (entry->ndl) {
			/* this is a safety stop as we still have ndl */
			if (entry->stoptime)
				put_format(b, translate("gettextFromC", "Safetystop: %umin @ %.0f%s\n"), DIV_UP(entry->stoptime, 60),
					   depthvalue, depth_unit);
			else
				put_format(b, translate("gettextFromC", "Safetystop: unkn time @ %.0f%s\n"),
					   depthvalue, depth_unit);
		} else {
			/* actual deco stop */
			if (entry->stoptime)
				put_format(b, translate("gettextFromC", "Deco: %umin @ %.0f%s\n"), DIV_UP(entry->stoptime, 60),
					   depthvalue, depth_unit);
			else
				put_format(b, translate("gettextFromC", "Deco: unkn time @ %.0f%s\n"),
					   depthvalue, depth_unit);
		}
	} else if (entry->in_deco) {
		put_string(b, translate("gettextFromC", "In deco\n"));
	} else if (has_ndl) {
		put_format(b, translate("gettextFromC", "NDL: %umin\n"), DIV_UP(entry->ndl, 60));
	}
	if (entry->tts)
		put_format(b, translate("gettextFromC", "TTS: %umin\n"), DIV_UP(entry->tts, 60));
	if (entry->stopdepth_calc && entry->stoptime_calc) {
		depthvalue = get_depth_units(entry->stopdepth_calc, NULL, &depth_unit);
		put_format(b, translate("gettextFromC", "Deco: %umin @ %.0f%s (calc)\n"), DIV_UP(entry->stoptime_calc, 60),
			   depthvalue, depth_unit);
	} else if (entry->in_deco_calc) {
		/* This means that we have no NDL left,
		 * and we have no deco stop,
		 * so if we just accend to the surface slowly
		 * (ascent_mm_per_step / ascent_s_per_step)
		 * everything will be ok. */
		put_string(b, translate("gettextFromC", "In deco (calc)\n"));
	} else if (prefs.calcndltts && entry->ndl_calc != 0) {
		if(entry->ndl_calc < MAX_PROFILE_DECO)
			put_format(b, translate("gettextFromC", "NDL: %umin (calc)\n"), DIV_UP(entry->ndl_calc, 60));
		else
			put_format(b, "%s", translate("gettextFromC", "NDL: >2h (calc)\n"));
	}
	if (entry->tts_calc) {
		if (entry->tts_calc < MAX_PROFILE_DECO)
			put_format(b, translate("gettextFromC", "TTS: %umin (calc)\n"), DIV_UP(entry->tts_calc, 60));
		else
			put_format(b, "%s", translate("gettextFromC", "TTS: >2h (calc)\n"));
	}
	if (entry->rbt)
		put_format(b, translate("gettextFromC", "RBT: %umin\n"), DIV_UP(entry->rbt, 60));
	if (entry->ceiling) {
		depthvalue = get_depth_units(entry->ceiling, NULL, &depth_unit);
		put_format(b, translate("gettextFromC", "Calculated ceiling %.0f%s\n"), depthvalue, depth_unit);
		if (prefs.calcalltissues) {
			int k;
			for (k = 0; k < 16; k++) {
				if (entry->ceilings[k]) {
					depthvalue = get_depth_units(entry->ceilings[k], NULL, &depth_unit);
					put_format(b, translate("gettextFromC", "Tissue %.0fmin: %.1f%s\n"), buehlmann_N2_t_halflife[k], depthvalue, depth_unit);
				}
			}
		}
	}
	if (entry->heartbeat && prefs.hrgraph)
		put_format(b, translate("gettextFromC", "heartbeat: %d\n"), entry->heartbeat);
	if (entry->bearing)
		put_format(b, translate("gettextFromC", "bearing: %d\n"), entry->bearing);
	if (entry->running_sum) {
		depthvalue = get_depth_units(entry->running_sum / entry->sec, NULL, &depth_unit);
		put_format(b, translate("gettextFromC", "mean depth to here %.1f%s\n"), depthvalue, depth_unit);
	}

	strip_mb(b);
}
Ejemplo n.º 9
0
void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
	// We don't have enougth data to calculate things, quit.
	if (!shouldCalculateStuff(topLeft, bottomRight))
		return;
	int last_index = -1;
	int o2mbar;
	QPolygonF boundingPoly, o2Poly; // This is the "Whole Item", but a pressure can be divided in N Polygons.
	polygons.clear();
	if (displayed_dive.dc.divemode == CCR)
		polygons.append(o2Poly);

	for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
		o2mbar = 0;
		plot_data *entry = dataModel->data().entry + i;
		int mbar = GET_PRESSURE(entry);
		if (displayed_dive.dc.divemode == CCR)
			o2mbar = GET_O2CYLINDER_PRESSURE(entry);

		if (entry->cylinderindex != last_index) {
			polygons.append(QPolygonF()); // this is the polygon that will be actually drawn on screen.
			last_index = entry->cylinderindex;
		}
		if (!mbar) {
			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));
		boundingPoly.push_back(point);    // The BoundingRect
		polygons.last().push_back(point); // The polygon thta will be plotted.
	}
	setPolygon(boundingPoly);
	qDeleteAll(texts);
	texts.clear();
	int mbar, cyl;
	int seen_cyl[MAX_CYLINDERS] = { false, };
	int last_pressure[MAX_CYLINDERS] = { 0, };
	int last_time[MAX_CYLINDERS] = { 0, };
	struct plot_data *entry;

	cyl = -1;
	o2mbar = 0;

	double print_y_offset[8][2] = { { 0, -0.5 }, { 0, -0.5 }, { 0, -0.5 }, { 0, -0.5 }, { 0, -0.5 } ,{ 0, -0.5 }, { 0, -0.5 }, { 0, -0.5 } };
	// CCR dives: These are offset values used to print the gas lables and pressures on a CCR dive profile at
	// appropriate Y-coordinates: One doublet of values for each of 8 cylinders.
	// Order of offsets within a doublet: gas lable offset; gas pressure offset.
	// The array is initialised with default values that apply to non-CCR dives.

	bool offsets_initialised = false;
	int o2cyl = -1, dilcyl = -1;
	QFlags<Qt::AlignmentFlag> alignVar= Qt::AlignTop, align_dil = Qt::AlignBottom, align_o2 = Qt::AlignTop;
	double axisRange = (vAxis->maximum() - vAxis->minimum())/1000;	// Convert axis pressure range to bar
	double axisLog = log10(log10(axisRange));
	for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
		entry = dataModel->data().entry + i;
		mbar = GET_PRESSURE(entry);
		if (displayed_dive.dc.divemode == CCR && displayed_dive.oxygen_cylinder_index >= 0)
			o2mbar = GET_O2CYLINDER_PRESSURE(entry);

		if (o2mbar) {	// If there is an o2mbar value then this is a CCR dive. Then do:
			// The first time an o2 value is detected, see if the oxygen cyl pressure graph starts above or below the dil graph
			if (!offsets_initialised) {	// Initialise the parameters for placing the text correctly near the graph line:
				o2cyl = displayed_dive.oxygen_cylinder_index;
				dilcyl = displayed_dive.diluent_cylinder_index;
				if ((o2mbar > mbar)) {	// If above, write o2 start cyl pressure above graph and diluent pressure below graph:
					print_y_offset[o2cyl][0] = -7 * axisLog; // y offset for oxygen gas lable (above); pressure offsets=-0.5, already initialised
					print_y_offset[dilcyl][0] = 5 * axisLog; // y offset for diluent gas lable (below)
				} else {				// ... else write o2 start cyl pressure below graph:
					print_y_offset[o2cyl][0]  = 5 * axisLog; // o2 lable & pressure below graph; pressure offsets=-0.5, already initialised
					print_y_offset[dilcyl][0] = -7.8 * axisLog;  // and diluent lable above graph.
					align_dil = Qt::AlignTop;
					align_o2  = Qt::AlignBottom;
				}
				offsets_initialised = true;
			}

			if (!seen_cyl[displayed_dive.oxygen_cylinder_index]) {	//For o2, on the left of profile, write lable and pressure
				plotPressureValue(o2mbar, entry->sec, align_o2, print_y_offset[o2cyl][1]);
				plotGasValue(o2mbar, entry->sec, displayed_dive.cylinder[displayed_dive.oxygen_cylinder_index].gasmix, align_o2, print_y_offset[o2cyl][0]);
				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;
			alignVar = align_dil;
		}

		if (!mbar)
			continue;

		if (cyl != entry->cylinderindex) {	// Pressure value near the left hand edge of the profile - other cylinders:
			cyl = entry->cylinderindex;	// For each other cylinder, write the gas lable and pressure
			if (!seen_cyl[cyl]) {
				plotPressureValue(mbar, entry->sec, alignVar, print_y_offset[cyl][1]);
				plotGasValue(mbar, entry->sec, displayed_dive.cylinder[cyl].gasmix, align_dil, print_y_offset[cyl][0]);
				seen_cyl[cyl] = true;
			}
		}
		last_pressure[cyl] = mbar;
		last_time[cyl] = entry->sec;
	}

	for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {	// For each cylinder, on right hand side of profile, write cylinder pressure
		alignVar = ((o2cyl >= 0) && (cyl == displayed_dive.oxygen_cylinder_index)) ? align_o2 : align_dil;
		if (last_time[cyl]) {
			plotPressureValue(last_pressure[cyl], last_time[cyl], (alignVar | Qt::AlignLeft), print_y_offset[cyl][1]);
		}
	}
}
Ejemplo n.º 10
0
void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
	// We don't have enougth data to calculate things, quit.
	if (!shouldCalculateStuff(topLeft, bottomRight))
		return;

	int plotted_cyl[MAX_CYLINDERS] = { false, };
	int last_plotted[MAX_CYLINDERS] = { 0, };
	QPolygonF poly[MAX_CYLINDERS];
	QPolygonF boundingPoly;
	polygons.clear();

	for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
		struct plot_data *entry = dataModel->data().entry + i;

		for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
			int mbar = GET_PRESSURE(entry, cyl);
			int time = entry->sec;

			if (!mbar)
				continue;

			QPointF point(hAxis->posAtValue(time), vAxis->posAtValue(mbar));
			boundingPoly.push_back(point);

			if (plotted_cyl[cyl]) {
				/* Have we used this culinder in the last two minutes? Continue */
				if (time - last_plotted[cyl] <= 2*60) {
					poly[cyl].push_back(point);
					last_plotted[cyl] = time;
					continue;
				}

				/* Finish the previous one, start a new one */
				polygons.append(poly[cyl]);
				poly[cyl] = QPolygonF();
			}

			plotted_cyl[cyl] = true;
			last_plotted[cyl] = time;
			poly[cyl].push_back(point);
		}
	}

	for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
		if (!plotted_cyl[cyl])
			continue;
		polygons.append(poly[cyl]);
	}

	setPolygon(boundingPoly);
	qDeleteAll(texts);
	texts.clear();

	int seen_cyl[MAX_CYLINDERS] = { false, };
	int last_pressure[MAX_CYLINDERS] = { 0, };
	int last_time[MAX_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
	// label and the gas pressure above and under the pressure line.
	// The values are historical, and we could try to pick the over/under
	// depending on whether this pressure is higher or lower than the average.
	// Right now it's just strictly alternating when you have multiple gas
	// pressures.

	QFlags<Qt::AlignmentFlag> alignVar = Qt::AlignTop;
	QFlags<Qt::AlignmentFlag> align[MAX_CYLINDERS];

	double axisRange = (vAxis->maximum() - vAxis->minimum())/1000;	// Convert axis pressure range to bar
	double axisLog = log10(log10(axisRange));

	for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
		struct plot_data *entry = dataModel->data().entry + i;

		for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
			int mbar = GET_PRESSURE(entry, cyl);

			if (!mbar)
				continue;

			if (!seen_cyl[cyl]) {
				double value_y_offset, label_y_offset;

				// Magic Y offset depending on whether we're aliging
				// the top of the text or the bottom of the text to
				// the pressure line.
				value_y_offset = -0.5;
				if (alignVar & Qt::AlignTop) {
					label_y_offset = 5 * axisLog;
				} else {
					label_y_offset = -7 * axisLog;
				}
				plotPressureValue(mbar, entry->sec, alignVar, value_y_offset);
				plotGasValue(mbar, entry->sec, displayed_dive.cylinder[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 < MAX_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);
		}
	}
}
Ejemplo n.º 11
0
void ProfileGraphicsView::plot_cylinder_pressure(struct divecomputer *dc)
{
	int i;
	int last = -1, last_index = -1;
	int lift_pen = FALSE;
	int first_plot = TRUE;
	int sac = 0;
	struct plot_data *last_entry = NULL;

	if (!get_cylinder_pressure_range(&gc))
		return;

	QPointF from, to;
	for (i = 0; i < gc.pi.nr; i++) {
		int mbar;
		struct plot_data *entry = gc.pi.entry + i;

		mbar = GET_PRESSURE(entry);
		if (entry->cylinderindex != last_index) {
			lift_pen = TRUE;
			last_entry = NULL;
		}
		if (!mbar) {
			lift_pen = TRUE;
			continue;
		}
		if (!last_entry) {
			last = i;
			last_entry = entry;
			sac = get_local_sac(entry, gc.pi.entry + i + 1, dive);
		} else {
			int j;
			sac = 0;
			for (j = last; j < i; j++)
				sac += get_local_sac(gc.pi.entry + j, gc.pi.entry + j + 1, dive);
			sac /= (i - last);
			if (entry->sec - last_entry->sec >= SAC_WINDOW) {
				last++;
				last_entry = gc.pi.entry + last;
			}
		}

		QColor c = get_sac_color(sac, dive->sac);

		if (lift_pen) {
			if (!first_plot && entry->cylinderindex == last_index) {
				/* if we have a previous event from the same tank,
				 * draw at least a short line */
				int prev_pr;
				prev_pr = GET_PRESSURE(entry - 1);

				QGraphicsLineItem *item = new QGraphicsLineItem(SCALEGC((entry-1)->sec, prev_pr), SCALEGC(entry->sec, mbar));
				QPen pen(defaultPen);
				pen.setColor(c);
				item->setPen(pen);
				scene()->addItem(item);
			} else {
				first_plot = FALSE;
				from = QPointF(SCALEGC(entry->sec, mbar));
			}
			lift_pen = FALSE;
		} else {
			to = QPointF(SCALEGC(entry->sec, mbar));
			QGraphicsLineItem *item = new QGraphicsLineItem(from.x(), from.y(), to.x(), to.y());
			QPen pen(defaultPen);
			pen.setColor(c);
			item->setPen(pen);
			scene()->addItem(item);
		}


		from = QPointF(SCALEGC(entry->sec, mbar));
		last_index = entry->cylinderindex;
	}
}