/* * 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); }
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); } } }
/* 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; }
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; } }
/* * 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); }
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); } } }
/* 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); }
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); }
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]); } } }
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); } } }
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; } }