summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--profile.c204
-rw-r--r--profile.h15
-rw-r--r--qt-ui/profilegraphics.cpp246
-rw-r--r--qt-ui/profilegraphics.h2
4 files changed, 251 insertions, 216 deletions
diff --git a/profile.c b/profile.c
index 3f413f4ed..be6efa1e6 100644
--- a/profile.c
+++ b/profile.c
@@ -58,11 +58,6 @@ struct plot_data {
#if USE_GTK_UI
-/* Scale to 0,0 -> maxx,maxy */
-#define SCALEX(gc,x) (((x)-gc->leftx)/(gc->rightx-gc->leftx)*gc->maxx)
-#define SCALEY(gc,y) (((y)-gc->topy)/(gc->bottomy-gc->topy)*gc->maxy)
-#define SCALE(gc,x,y) SCALEX(gc,x),SCALEY(gc,y)
-
/* keep the last used gc around so we can invert the SCALEX calculation in
* order to calculate a time value for an x coordinate */
static struct graphics_context last_gc;
@@ -611,205 +606,6 @@ static void plot_pp_gas_profile(struct graphics_context *gc, struct plot_info *p
}
}
-static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi)
-{
- int i, incr;
- cairo_t *cr = gc->cr;
- 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(pi);
- maxdepth = get_maxdepth(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;
-
- set_source_rgba(gc, TIME_GRID);
- cairo_set_line_width_scaled(gc->cr, 2);
-
- for (i = incr; i < maxtime; i += incr) {
- move_to(gc, i, 0);
- line_to(gc, i, 1);
- }
- cairo_stroke(cr);
-
- /* now the text on the time markers */
- text_render_options_t tro = {DEPTH_TEXT_SIZE, TIME_TEXT, CENTER, TOP};
- if (maxtime < 600) {
- /* Be a bit more verbose with shorter dives */
- for (i = incr; i < maxtime; i += incr)
- plot_text(gc, &tro, i, 1, "%02d:%02d", i/60, i%60);
- } else {
- /* Only render the time on every second marker for normal dives */
- for (i = incr; i < maxtime; i += 2 * incr)
- plot_text(gc, &tro, i, 1, "%d", i/60);
- }
- /* 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 METERS: marker = 10000; break;
- case FEET: marker = 9144; break; /* 30 ft */
- }
- maxline = MAX(pi->maxdepth + marker, maxdepth * 2 / 3);
- set_source_rgba(gc, DEPTH_GRID);
- for (i = marker; i < maxline; i += marker) {
- move_to(gc, 0, i);
- line_to(gc, 1, i);
- }
- cairo_stroke(cr);
-
- gc->leftx = 0; gc->rightx = maxtime;
-
- /* Show mean depth */
- if (! gc->printer) {
- set_source_rgba(gc, MEAN_DEPTH);
- move_to(gc, 0, pi->meandepth);
- line_to(gc, pi->entry[pi->nr - 1].sec, pi->meandepth);
- cairo_stroke(cr);
- }
-
- /*
- * 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);
- }
-
- /* Do the depth profile for the neat fill */
- gc->topy = 0; gc->bottomy = maxdepth;
-
- cairo_pattern_t *pat;
- pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
- pattern_add_color_stop_rgba (gc, pat, 1, DEPTH_BOTTOM);
- pattern_add_color_stop_rgba (gc, pat, 0, DEPTH_TOP);
-
- cairo_set_source(gc->cr, pat);
- cairo_pattern_destroy(pat);
- cairo_set_line_width_scaled(gc->cr, 2);
-
- entry = pi->entry;
- move_to(gc, 0, 0);
- for (i = 0; i < pi->nr; i++, entry++)
- line_to(gc, entry->sec, entry->depth);
-
- /* Show any ceiling we may have encountered */
- for (i = pi->nr - 1; i >= 0; i--, entry--) {
- if (entry->ndl) {
- /* non-zero NDL implies this is a safety stop, no ceiling */
- line_to(gc, entry->sec, 0);
- } else if (entry->stopdepth < entry->depth) {
- line_to(gc, entry->sec, entry->stopdepth);
- } else {
- line_to(gc, entry->sec, entry->depth);
- }
- }
- cairo_close_path(gc->cr);
- cairo_fill(gc->cr);
-
- /* 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_red_ceiling) {
- pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
- pattern_add_color_stop_rgba (gc, pat, 0, CEILING_SHALLOW);
- pattern_add_color_stop_rgba (gc, pat, 1, CEILING_DEEP);
- cairo_set_source(gc->cr, pat);
- cairo_pattern_destroy(pat);
- entry = pi->entry;
- move_to(gc, 0, 0);
- for (i = 0; i < pi->nr; i++, entry++) {
- if (entry->ndl == 0 && entry->stopdepth) {
- if (entry->ndl == 0 && entry->stopdepth < entry->depth) {
- line_to(gc, entry->sec, entry->stopdepth);
- } else {
- line_to(gc, entry->sec, entry->depth);
- }
- } else {
- line_to(gc, entry->sec, 0);
- }
- }
- cairo_close_path(gc->cr);
- cairo_fill(gc->cr);
- }
- /* finally, plot the calculated ceiling over all this */
- if (prefs.profile_calc_ceiling) {
- pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
- pattern_add_color_stop_rgba (gc, pat, 0, CALC_CEILING_SHALLOW);
- pattern_add_color_stop_rgba (gc, pat, 1, CALC_CEILING_DEEP);
- cairo_set_source(gc->cr, pat);
- cairo_pattern_destroy(pat);
- entry = pi->entry;
- move_to(gc, 0, 0);
- for (i = 0; i < pi->nr; i++, entry++) {
- if (entry->ceiling)
- line_to(gc, entry->sec, entry->ceiling);
- else
- line_to(gc, entry->sec, 0);
- }
- line_to(gc, (entry-1)->sec, 0); /* make sure we end at 0 */
- cairo_close_path(gc->cr);
- cairo_fill(gc->cr);
- }
- /* next show where we have been bad and crossed the dc's ceiling */
- pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
- pattern_add_color_stop_rgba (gc, pat, 0, CEILING_SHALLOW);
- pattern_add_color_stop_rgba (gc, pat, 1, CEILING_DEEP);
- cairo_set_source(gc->cr, pat);
- cairo_pattern_destroy(pat);
- entry = pi->entry;
- move_to(gc, 0, 0);
- for (i = 0; i < pi->nr; i++, entry++)
- line_to(gc, entry->sec, entry->depth);
-
- for (i = pi->nr - 1; i >= 0; i--, entry--) {
- if (entry->ndl == 0 && entry->stopdepth > entry->depth) {
- line_to(gc, entry->sec, entry->stopdepth);
- } else {
- line_to(gc, entry->sec, entry->depth);
- }
- }
- cairo_close_path(gc->cr);
- cairo_fill(gc->cr);
-
- /* Now do it again for the velocity colors */
- entry = pi->entry;
- for (i = 1; i < 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;
- set_source_rgba(gc, VELOCITY_COLORS_START_IDX + entry->velocity);
- move_to(gc, entry[-1].sec, entry[-1].depth);
- line_to(gc, sec, depth);
- cairo_stroke(cr);
- }
-}
static int setup_temperature_limits(struct graphics_context *gc, struct plot_info *pi)
{
diff --git a/profile.h b/profile.h
index 66d1ee190..1ad6625db 100644
--- a/profile.h
+++ b/profile.h
@@ -19,6 +19,21 @@ struct plot_info;
void calculate_max_limits(struct dive *dive, struct divecomputer *dc, struct graphics_context *gc);
struct plot_info *create_plot_info(struct dive *dive, struct divecomputer *dc, struct graphics_context *gc);
+/*
+ * When showing dive profiles, we scale things to the
+ * current dive. However, we don't scale past less than
+ * 30 minutes or 90 ft, just so that small dives show
+ * up as such unless zoom is enabled.
+ * We also need to add 180 seconds at the end so the min/max
+ * plots correctly
+ */
+int get_maxtime(struct plot_info *pi);
+
+/* get the maximum depth to which we want to plot
+ * take into account the additional verical space needed to plot
+ * partial pressure graphs */
+int get_maxdepth(struct plot_info *pi);
+
#ifdef __cplusplus
}
#endif
diff --git a/qt-ui/profilegraphics.cpp b/qt-ui/profilegraphics.cpp
index e500432fc..f9d528831 100644
--- a/qt-ui/profilegraphics.cpp
+++ b/qt-ui/profilegraphics.cpp
@@ -2,7 +2,9 @@
#include <QGraphicsScene>
#include <QResizeEvent>
-
+#include <QGraphicsLineItem>
+#include <QPen>
+#include <QBrush>
#include <QDebug>
#include "../color.h"
@@ -15,6 +17,12 @@
#define VELOCITY_COLORS_START_IDX VELO_STABLE
#define VELOCITY_COLORS 5
+/* Scale to 0,0 -> maxx,maxy */
+#define SCALEX(gc,x) (((x)-gc->leftx)/(gc->rightx-gc->leftx)*gc->maxx)
+#define SCALEY(gc,y) (((y)-gc->topy)/(gc->bottomy-gc->topy)*gc->maxy)
+#define SCALE(gc,x,y) SCALEX(gc,x),SCALEY(gc,y)
+
+static struct graphics_context last_gc;
static double plot_scale = SCALE_SCREEN;
typedef enum {
@@ -93,6 +101,7 @@ void fill_profile_color()
ProfileGraphicsView::ProfileGraphicsView(QWidget* parent) : QGraphicsView(parent)
{
setScene(new QGraphicsScene());
+ setBackgroundBrush(QColor("#F3F3E6"));
scene()->setSceneRect(0,0,100,100);
fill_profile_color();
}
@@ -112,6 +121,13 @@ static void plot_set_scale(scale_mode_t scale)
void ProfileGraphicsView::plot(struct dive *dive)
{
+ // Clear the items before drawing this dive.
+ qDeleteAll(scene()->items());
+ scene()->clear();
+
+ if(!dive)
+ return;
+
struct plot_info *pi;
struct divecomputer *dc = &dive->dc;
@@ -151,13 +167,6 @@ void ProfileGraphicsView::plot(struct dive *dive)
*/
calculate_max_limits(dive, dc, &gc);
-#if 0
- /* shift the drawing area so we have a nice margin around it */
- cairo_translate(gc->cr, drawing_area->x, drawing_area->y);
- cairo_set_line_width_scaled(gc->cr, 1);
- cairo_set_line_cap(gc->cr, CAIRO_LINE_CAP_ROUND);
- cairo_set_line_join(gc->cr, CAIRO_LINE_JOIN_ROUND);
-
/*
* We don't use "cairo_translate()" because that doesn't
* scale line width etc. But the actual scaling we need
@@ -165,16 +174,18 @@ void ProfileGraphicsView::plot(struct dive *dive)
*
* Snif. What a pity.
*/
- gc->maxx = (drawing_area->width - 2*drawing_area->x);
- gc->maxy = (drawing_area->height - 2*drawing_area->y);
+ QRectF drawing_area = scene()->sceneRect();
+ gc.maxx = (drawing_area.width() - 2 * drawing_area.x());
+ gc.maxy = (drawing_area.height() - 2 * drawing_area.y());
dc = select_dc(dc);
/* This is per-dive-computer. Right now we just do the first one */
- pi = create_plot_info(dive, dc, gc);
+ pi = create_plot_info(dive, dc, &gc);
/* Depth profile */
- plot_depth_profile(gc, pi);
+ plot_depth_profile(&gc, pi);
+#if 0
plot_events(gc, pi, dc);
/* Temperature profile */
@@ -233,6 +244,217 @@ void ProfileGraphicsView::plot(struct dive *dive)
#endif
}
+
+void ProfileGraphicsView::plot_depth_profile(struct graphics_context *gc, struct plot_info *pi)
+{
+ 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(pi);
+ maxdepth = get_maxdepth(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 color;
+ color = profile_color[TIME_GRID].at(0);
+ for (i = incr; i < maxtime; i += incr) {
+ QGraphicsLineItem *line = new QGraphicsLineItem(SCALE(gc, i, 0), SCALE(gc, i, 1));
+ line->setPen(QPen(color));
+ scene()->addItem(line);
+ }
+
+#if 0
+ /* now the text on the time markers */
+ text_render_options_t tro = {DEPTH_TEXT_SIZE, TIME_TEXT, CENTER, TOP};
+ if (maxtime < 600) {
+ /* Be a bit more verbose with shorter dives */
+ for (i = incr; i < maxtime; i += incr)
+ plot_text(gc, &tro, i, 1, "%02d:%02d", i/60, i%60);
+ } else {
+ /* Only render the time on every second marker for normal dives */
+ for (i = incr; i < maxtime; i += 2 * incr)
+ plot_text(gc, &tro, i, 1, "%d", i/60);
+ }
+#endif
+
+ /* 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 = MAX(pi->maxdepth + marker, maxdepth * 2 / 3);
+
+ color = profile_color[TIME_GRID].at(0);
+
+ for (i = marker; i < maxline; i += marker) {
+ QGraphicsLineItem *line = new QGraphicsLineItem(SCALE(gc, 0, i), SCALE(gc, 1, i));
+ line->setPen(QPen(color));
+ scene()->addItem(line);
+ }
+
+#if 0
+ gc->leftx = 0; gc->rightx = maxtime;
+
+ /* Show mean depth */
+ if (! gc->printer) {
+ set_source_rgba(gc, MEAN_DEPTH);
+ move_to(gc, 0, pi->meandepth);
+ line_to(gc, pi->entry[pi->nr - 1].sec, pi->meandepth);
+ cairo_stroke(cr);
+ }
+
+ /*
+ * 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);
+ }
+
+ /* Do the depth profile for the neat fill */
+ gc->topy = 0; gc->bottomy = maxdepth;
+
+ cairo_pattern_t *pat;
+ pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
+ pattern_add_color_stop_rgba (gc, pat, 1, DEPTH_BOTTOM);
+ pattern_add_color_stop_rgba (gc, pat, 0, DEPTH_TOP);
+
+ cairo_set_source(gc->cr, pat);
+ cairo_pattern_destroy(pat);
+ cairo_set_line_width_scaled(gc->cr, 2);
+
+ entry = pi->entry;
+ move_to(gc, 0, 0);
+ for (i = 0; i < pi->nr; i++, entry++)
+ line_to(gc, entry->sec, entry->depth);
+
+ /* Show any ceiling we may have encountered */
+ for (i = pi->nr - 1; i >= 0; i--, entry--) {
+ if (entry->ndl) {
+ /* non-zero NDL implies this is a safety stop, no ceiling */
+ line_to(gc, entry->sec, 0);
+ } else if (entry->stopdepth < entry->depth) {
+ line_to(gc, entry->sec, entry->stopdepth);
+ } else {
+ line_to(gc, entry->sec, entry->depth);
+ }
+ }
+ cairo_close_path(gc->cr);
+ cairo_fill(gc->cr);
+
+ /* 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_red_ceiling) {
+ pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
+ pattern_add_color_stop_rgba (gc, pat, 0, CEILING_SHALLOW);
+ pattern_add_color_stop_rgba (gc, pat, 1, CEILING_DEEP);
+ cairo_set_source(gc->cr, pat);
+ cairo_pattern_destroy(pat);
+ entry = pi->entry;
+ move_to(gc, 0, 0);
+ for (i = 0; i < pi->nr; i++, entry++) {
+ if (entry->ndl == 0 && entry->stopdepth) {
+ if (entry->ndl == 0 && entry->stopdepth < entry->depth) {
+ line_to(gc, entry->sec, entry->stopdepth);
+ } else {
+ line_to(gc, entry->sec, entry->depth);
+ }
+ } else {
+ line_to(gc, entry->sec, 0);
+ }
+ }
+ cairo_close_path(gc->cr);
+ cairo_fill(gc->cr);
+ }
+ /* finally, plot the calculated ceiling over all this */
+ if (prefs.profile_calc_ceiling) {
+ pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
+ pattern_add_color_stop_rgba (gc, pat, 0, CALC_CEILING_SHALLOW);
+ pattern_add_color_stop_rgba (gc, pat, 1, CALC_CEILING_DEEP);
+ cairo_set_source(gc->cr, pat);
+ cairo_pattern_destroy(pat);
+ entry = pi->entry;
+ move_to(gc, 0, 0);
+ for (i = 0; i < pi->nr; i++, entry++) {
+ if (entry->ceiling)
+ line_to(gc, entry->sec, entry->ceiling);
+ else
+ line_to(gc, entry->sec, 0);
+ }
+ line_to(gc, (entry-1)->sec, 0); /* make sure we end at 0 */
+ cairo_close_path(gc->cr);
+ cairo_fill(gc->cr);
+ }
+ /* next show where we have been bad and crossed the dc's ceiling */
+ pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
+ pattern_add_color_stop_rgba (gc, pat, 0, CEILING_SHALLOW);
+ pattern_add_color_stop_rgba (gc, pat, 1, CEILING_DEEP);
+ cairo_set_source(gc->cr, pat);
+ cairo_pattern_destroy(pat);
+ entry = pi->entry;
+ move_to(gc, 0, 0);
+ for (i = 0; i < pi->nr; i++, entry++)
+ line_to(gc, entry->sec, entry->depth);
+
+ for (i = pi->nr - 1; i >= 0; i--, entry--) {
+ if (entry->ndl == 0 && entry->stopdepth > entry->depth) {
+ line_to(gc, entry->sec, entry->stopdepth);
+ } else {
+ line_to(gc, entry->sec, entry->depth);
+ }
+ }
+ cairo_close_path(gc->cr);
+ cairo_fill(gc->cr);
+
+ /* Now do it again for the velocity colors */
+ entry = pi->entry;
+ for (i = 1; i < 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;
+ set_source_rgba(gc, VELOCITY_COLORS_START_IDX + entry->velocity);
+ move_to(gc, entry[-1].sec, entry[-1].depth);
+ line_to(gc, sec, depth);
+ cairo_stroke(cr);
+ }
+#endif
+}
+
+
void ProfileGraphicsView::resizeEvent(QResizeEvent *event)
{
// Fits the scene's rectangle on the view.
diff --git a/qt-ui/profilegraphics.h b/qt-ui/profilegraphics.h
index e3380abcd..633409b23 100644
--- a/qt-ui/profilegraphics.h
+++ b/qt-ui/profilegraphics.h
@@ -12,6 +12,8 @@ public:
protected:
void resizeEvent(QResizeEvent *event);
+private:
+ void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi);
};
#endif