void ProfileGraphicsView::plot_temperature_profile() { int last = 0; if (!setup_temperature_limits(&gc)) return; QPointF from; QPointF to; QColor color = getColor(TEMP_PLOT); for (int i = 0; i < gc.pi.nr; i++) { struct plot_data *entry = gc.pi.entry + i; int mkelvin = entry->temperature; int sec = entry->sec; if (!mkelvin) { if (!last) continue; mkelvin = last; } if (last) { to = QPointF(SCALEGC(sec, mkelvin)); QGraphicsLineItem *item = new QGraphicsLineItem(from.x(), from.y(), to.x(), to.y()); QPen pen(defaultPen); pen.setColor(color); item->setPen(pen); scene()->addItem(item); from = to; } else { from = QPointF(SCALEGC(sec, mkelvin)); } last = mkelvin; } }
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; } }
QGraphicsItemGroup *ProfileGraphicsView::plot_text(text_render_options_t *tro,const QPointF& pos, const QString& text, QGraphicsItem *parent) { QFont fnt(font()); QFontMetrics fm(fnt); if (printMode) fnt.setPixelSize(tro->size); QPointF point(SCALEGC(pos.x(), pos.y())); // This is neded because of the SCALE macro. double dx = tro->hpos * (fm.width(text)); double dy = tro->vpos * (fm.height()); QGraphicsItemGroup *group = new QGraphicsItemGroup(parent); QPainterPath textPath; /* addText() uses bottom-left text baseline and the -3 offset is probably slightly off * for different font sizes. */ textPath.addText(0, fm.height() - 3, fnt, text); QPainterPathStroker stroker; stroker.setWidth(3); QGraphicsPathItem *strokedItem = new QGraphicsPathItem(stroker.createStroke(textPath), group); strokedItem->setBrush(QBrush(getColor(TEXT_BACKGROUND))); strokedItem->setPen(Qt::NoPen); QGraphicsPathItem *textItem = new QGraphicsPathItem(textPath, group); textItem->setBrush(QBrush(getColor(tro->color))); textItem->setPen(Qt::NoPen); group->setPos(point.x() + dx, point.y() + dy); if (!printMode) group->setFlag(QGraphicsItem::ItemIgnoresTransformations); if (!parent) scene()->addItem(group); return group; }
void ProfileGraphicsView::plot_add_line(int sec, double val, QColor c, QPointF &from) { QPointF to = QPointF(SCALEGC(sec, val)); 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 = to; }
void ProfileGraphicsView::plot_pp_text() { double pp, dpp, m; int hpos; static text_render_options_t tro = {PP_TEXT_SIZE, PP_LINES, LEFT, MIDDLE}; setup_pp_limits(&gc); pp = floor(gc.pi.maxpp * 10.0) / 10.0 + 0.2; dpp = pp > 4 ? 1.0 : 0.5; hpos = gc.pi.entry[gc.pi.nr - 1].sec; QColor c = profile_color[PP_LINES].first(); for (m = 0.0; m <= pp; m += dpp) { QGraphicsLineItem *item = new QGraphicsLineItem(SCALEGC(0, m), SCALEGC(hpos, m)); QPen pen(defaultPen); pen.setColor(c); item->setPen(pen); scene()->addItem(item); plot_text(&tro, QPointF(hpos + 30, m), QString::number(m)); } }
void ProfileGraphicsView::plot_depth_profile() { int i, incr; int sec, depth; struct plot_data *entry; int maxtime, maxdepth, marker, maxline; int increments[8] = { 10, 20, 30, 60, 5*60, 10*60, 15*60, 30*60 }; /* Get plot scaling limits */ maxtime = get_maxtime(&gc.pi); maxdepth = get_maxdepth(&gc.pi); gc.maxtime = maxtime; /* Time markers: at most every 10 seconds, but no more than 12 markers. * We start out with 10 seconds and increment up to 30 minutes, * depending on the dive time. * This allows for 6h dives - enough (I hope) for even the craziest * divers - but just in case, for those 8h depth-record-breaking dives, * we double the interval if this still doesn't get us to 12 or fewer * time markers */ i = 0; while (maxtime / increments[i] > 12 && i < 7) i++; incr = increments[i]; while (maxtime / incr > 12) incr *= 2; gc.leftx = 0; gc.rightx = maxtime; gc.topy = 0; gc.bottomy = 1.0; last_gc = gc; QColor c = getColor(TIME_GRID); for (i = incr; i < maxtime; i += incr) { QGraphicsLineItem *item = new QGraphicsLineItem(SCALEGC(i, 0), SCALEGC(i, 1)); QPen pen(defaultPen); pen.setColor(c); item->setPen(pen); scene()->addItem(item); } timeMarkers = new QGraphicsRectItem(); /* now the text on the time markers */ struct text_render_options tro = {DEPTH_TEXT_SIZE, TIME_TEXT, CENTER, LINE_DOWN}; if (maxtime < 600) { /* Be a bit more verbose with shorter dives */ for (i = incr; i < maxtime; i += incr) plot_text(&tro, QPointF(i, 0), QString("%1:%2").arg(i/60).arg(i%60, 2, 10, QChar('0')), timeMarkers); } else { /* Only render the time on every second marker for normal dives */ for (i = incr; i < maxtime; i += 2 * incr) plot_text(&tro, QPointF(i, 0), QString("%1").arg(QString::number(i/60)), timeMarkers); } timeMarkers->setPos(0,0); scene()->addItem(timeMarkers); /* Depth markers: every 30 ft or 10 m*/ gc.leftx = 0; gc.rightx = 1.0; gc.topy = 0; gc.bottomy = maxdepth; switch (prefs.units.length) { case units::METERS: marker = 10000; break; case units::FEET: marker = 9144; break; /* 30 ft */ } maxline = qMax(gc.pi.maxdepth + marker, maxdepth * 2 / 3); c = getColor(DEPTH_GRID); for (i = marker; i < maxline; i += marker) { QGraphicsLineItem *item = new QGraphicsLineItem(SCALEGC(0, i), SCALEGC(1, i)); QPen pen(defaultPen); pen.setColor(c); item->setPen(pen); scene()->addItem(item); } gc.leftx = 0; gc.rightx = maxtime; c = getColor(MEAN_DEPTH); /* Show mean depth */ if (! gc.printer) { QGraphicsLineItem *item = new QGraphicsLineItem(SCALEGC(0, gc.pi.meandepth), SCALEGC(gc.pi.entry[gc.pi.nr - 1].sec, gc.pi.meandepth)); QPen pen(defaultPen); pen.setColor(c); item->setPen(pen); scene()->addItem(item); } #if 0 /* * These are good for debugging text placement etc, * but not for actual display.. */ if (0) { plot_smoothed_profile(gc, pi); plot_minmax_profile(gc, pi); } #endif /* Do the depth profile for the neat fill */ gc.topy = 0; gc.bottomy = maxdepth; entry = gc.pi.entry; QPolygonF p; QLinearGradient pat(0.0,0.0,0.0,scene()->height()); QGraphicsPolygonItem *neatFill = NULL; p.append(QPointF(SCALEGC(0, 0))); for (i = 0; i < gc.pi.nr; i++, entry++) p.append(QPointF(SCALEGC(entry->sec, entry->depth))); /* Show any ceiling we may have encountered */ if (prefs.profile_dc_ceiling) { for (i = gc.pi.nr - 1; i >= 0; i--, entry--) { if (!entry->in_deco) { /* not in deco implies this is a safety stop, no ceiling */ p.append(QPointF(SCALEGC(entry->sec, 0))); } else if (entry->stopdepth < entry->depth) { p.append(QPointF(SCALEGC(entry->sec, entry->stopdepth))); } else { p.append(QPointF(SCALEGC(entry->sec, entry->depth))); } } } pat.setColorAt(1, getColor(DEPTH_BOTTOM)); pat.setColorAt(0, getColor(DEPTH_TOP)); neatFill = new QGraphicsPolygonItem(); neatFill->setPolygon(p); neatFill->setBrush(QBrush(pat)); neatFill->setPen(QPen(QBrush(Qt::transparent),0)); scene()->addItem(neatFill); /* if the user wants the deco ceiling more visible, do that here (this * basically draws over the background that we had allowed to shine * through so far) */ if (prefs.profile_dc_ceiling && prefs.profile_red_ceiling) { p.clear(); pat.setColorAt(0, getColor(CEILING_SHALLOW)); pat.setColorAt(1, getColor(CEILING_DEEP)); entry = gc.pi.entry; p.append(QPointF(SCALEGC(0, 0))); for (i = 0; i < gc.pi.nr; i++, entry++) { if (entry->in_deco && entry->stopdepth) { if (entry->stopdepth < entry->depth) { p.append(QPointF(SCALEGC(entry->sec, entry->stopdepth))); } else { p.append(QPointF(SCALEGC(entry->sec, entry->depth))); } } else { p.append(QPointF(SCALEGC(entry->sec, 0))); } } neatFill = new QGraphicsPolygonItem(); neatFill->setBrush(QBrush(pat)); neatFill->setPolygon(p); neatFill->setPen(QPen(QBrush(Qt::NoBrush),0)); scene()->addItem(neatFill); } /* finally, plot the calculated ceiling over all this */ if (prefs.profile_calc_ceiling) { pat.setColorAt(0, getColor(CALC_CEILING_SHALLOW)); pat.setColorAt(1, getColor(CALC_CEILING_DEEP)); entry = gc.pi.entry; p.clear(); p.append(QPointF(SCALEGC(0, 0))); for (i = 0; i < gc.pi.nr; i++, entry++) { if (entry->ceiling) p.append(QPointF(SCALEGC(entry->sec, entry->ceiling))); else p.append(QPointF(SCALEGC(entry->sec, 0))); } p.append(QPointF(SCALEGC((entry-1)->sec, 0))); neatFill = new QGraphicsPolygonItem(); neatFill->setPolygon(p); neatFill->setPen(QPen(QBrush(Qt::NoBrush),0)); neatFill->setBrush(pat); scene()->addItem(neatFill); } /* plot the calculated ceiling for all tissues */ if (prefs.profile_calc_ceiling && prefs.calc_all_tissues) { int k; for (k=0; k<16; k++) { pat.setColorAt(0, getColor(CALC_CEILING_SHALLOW)); pat.setColorAt(1, QColor(100, 100, 100, 50)); entry = gc.pi.entry; p.clear(); p.append(QPointF(SCALEGC(0, 0))); for (i = 0; i < gc.pi.nr; i++, entry++) { if ((entry->ceilings)[k]) p.append(QPointF(SCALEGC(entry->sec, (entry->ceilings)[k]))); else p.append(QPointF(SCALEGC(entry->sec, 0))); } p.append(QPointF(SCALEGC((entry-1)->sec, 0))); neatFill = new QGraphicsPolygonItem(); neatFill->setPolygon(p); neatFill->setBrush(pat); scene()->addItem(neatFill); } } /* next show where we have been bad and crossed the dc's ceiling */ if (prefs.profile_dc_ceiling) { pat.setColorAt(0, getColor(CEILING_SHALLOW)); pat.setColorAt(1, getColor(CEILING_DEEP)); entry = gc.pi.entry; p.clear(); p.append(QPointF(SCALEGC(0, 0))); for (i = 0; i < gc.pi.nr; i++, entry++) p.append(QPointF(SCALEGC(entry->sec, entry->depth))); for (i-- , entry--; i >= 0; i--, entry--) { if (entry->in_deco && entry->stopdepth > entry->depth) { p.append(QPointF(SCALEGC(entry->sec, entry->stopdepth))); } else { p.append(QPointF(SCALEGC(entry->sec, entry->depth))); } } } neatFill = new QGraphicsPolygonItem(); neatFill->setPolygon(p); neatFill->setPen(QPen(QBrush(Qt::NoBrush),0)); neatFill->setBrush(QBrush(pat)); scene()->addItem(neatFill); /* Now do it again for the velocity colors */ entry = gc.pi.entry; for (i = 1; i < gc.pi.nr; i++) { entry++; sec = entry->sec; /* we want to draw the segments in different colors * representing the vertical velocity, so we need to * chop this into short segments */ depth = entry->depth; QGraphicsLineItem *item = new QGraphicsLineItem(SCALEGC(entry[-1].sec, entry[-1].depth), SCALEGC(sec, depth)); QPen pen(defaultPen); pen.setColor(getColor((color_indice_t)(VELOCITY_COLORS_START_IDX + entry->velocity))); item->setPen(pen); scene()->addItem(item); } }
void ProfileGraphicsView::plot_pp_gas_profile() { int i; struct plot_data *entry; struct plot_info *pi = &gc.pi; setup_pp_limits(&gc); QColor c; QPointF from, to; if (prefs.pp_graphs.pn2) { c = getColor(PN2); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->pn2)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->pn2 < prefs.pp_graphs.pn2_threshold) plot_add_line(entry->sec, entry->pn2, c, from); else from = QPointF(SCALEGC(entry->sec, entry->pn2)); } c = getColor(PN2_ALERT); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->pn2)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->pn2 >= prefs.pp_graphs.pn2_threshold) plot_add_line(entry->sec, entry->pn2, c, from); else from = QPointF(SCALEGC(entry->sec, entry->pn2)); } } if (prefs.pp_graphs.phe) { c = getColor(PHE); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->phe)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->phe < prefs.pp_graphs.phe_threshold) plot_add_line(entry->sec, entry->phe, c, from); else from = QPointF(SCALEGC(entry->sec, entry->phe)); } c = getColor(PHE_ALERT); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->phe)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->phe >= prefs.pp_graphs.phe_threshold) plot_add_line(entry->sec, entry->phe, c, from); else from = QPointF(SCALEGC(entry->sec, entry->phe)); } } if (prefs.pp_graphs.po2) { c = getColor(PO2); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->po2)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->po2 < prefs.pp_graphs.po2_threshold) plot_add_line(entry->sec, entry->po2, c, from); else from = QPointF(SCALEGC(entry->sec, entry->po2)); } c = getColor(PO2_ALERT); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->po2)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->po2 >= prefs.pp_graphs.po2_threshold) plot_add_line(entry->sec, entry->po2, c, from); else from = QPointF(SCALEGC(entry->sec, entry->po2)); } } }
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; } }
void ProfileGraphicsView::plot_pp_gas_profile() { int i; struct plot_data *entry; struct plot_info *pi = &gc.pi; setup_pp_limits(&gc); QColor c; QPointF from, to; if (prefs.pp_graphs.pn2) { c = profile_color[PN2].first(); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->pn2)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->pn2 < prefs.pp_graphs.pn2_threshold) { to = QPointF(SCALEGC(entry->sec, entry->pn2)); 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 = to; } else { from = QPointF(SCALEGC(entry->sec, entry->pn2)); } } c = profile_color[PN2_ALERT].first(); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->pn2)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->pn2 >= prefs.pp_graphs.pn2_threshold) { to = QPointF(SCALEGC(entry->sec, entry->pn2)); 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 = to; } else { from = QPointF(SCALEGC(entry->sec, entry->pn2)); } } } if (prefs.pp_graphs.phe) { c = profile_color[PHE].first(); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->phe)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->phe < prefs.pp_graphs.phe_threshold) { to = QPointF(SCALEGC(entry->sec, entry->phe)); 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 = to; } else { from = QPointF(SCALEGC(entry->sec, entry->phe)); } } c = profile_color[PHE_ALERT].first(); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->phe)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->phe >= prefs.pp_graphs.phe_threshold) { to = QPointF(SCALEGC(entry->sec, entry->phe)); 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 = to; } else { from = QPointF(SCALEGC(entry->sec, entry->phe)); } } } if (prefs.pp_graphs.po2) { c = profile_color[PO2].first(); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->po2)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->po2 < prefs.pp_graphs.po2_threshold) { to = QPointF(SCALEGC(entry->sec, entry->po2)); 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 = to; } else { from = QPointF(SCALEGC(entry->sec, entry->po2)); } } c = profile_color[PO2_ALERT].first(); entry = pi->entry; from = QPointF(SCALEGC(entry->sec, entry->po2)); for (i = 1; i < pi->nr; i++) { entry++; if (entry->po2 >= prefs.pp_graphs.po2_threshold) { to = QPointF(SCALEGC(entry->sec, entry->po2)); QGraphicsLineItem *item = new QGraphicsLineItem(from.x(), from.y(), to.x(), to.y()); item->setPen(QPen(c)); scene()->addItem(item); from = to; } else { from = QPointF(SCALEGC(entry->sec, entry->po2)); } } } }