10 #define ROUND_UP(x,y) ((((x)+(y)-1)/(y))*(y))
13 * When showing dive profiles, we scale things to the
14 * current dive. However, we don't scale past less than
15 * 30 minutes or 90 ft, just so that small dives show
18 static int round_seconds_up(int seconds)
20 return MAX(30*60, ROUND_UP(seconds, 60*10));
23 static int round_feet_up(int feet)
25 return MAX(90, ROUND_UP(feet+5, 15));
28 /* Scale to 0,0 -> maxx,maxy */
29 #define SCALE(x,y) (x)*maxx/scalex+topx,(y)*maxy/scaley+topy
31 static void plot_profile(struct dive *dive, cairo_t *cr,
32 double topx, double topy, double maxx, double maxy)
34 double scalex, scaley;
35 int begins, sec, depth;
37 struct sample *sample;
38 int maxtime, maxdepth;
40 samples = dive->samples;
44 cairo_set_line_width(cr, 2);
46 /* Get plot scaling limits */
47 maxtime = round_seconds_up(dive->duration.seconds);
48 maxdepth = round_feet_up(to_feet(dive->maxdepth));
50 /* Time markers: every 5 min */
53 for (i = 5*60; i < maxtime; i += 5*60) {
54 cairo_move_to(cr, SCALE(i, 0));
55 cairo_line_to(cr, SCALE(i, 1));
58 /* Depth markers: every 15 ft */
61 cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
62 for (i = 15; i < maxdepth; i += 15) {
63 cairo_move_to(cr, SCALE(0, i));
64 cairo_line_to(cr, SCALE(1, i));
69 cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.40);
70 cairo_move_to(cr, SCALE(0, to_feet(dive->meandepth)));
71 cairo_line_to(cr, SCALE(1, to_feet(dive->meandepth)));
76 sample = dive->sample;
77 cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.80);
78 begins = sample->time.seconds;
79 cairo_move_to(cr, SCALE(sample->time.seconds, to_feet(sample->depth)));
80 for (i = 1; i < dive->samples; i++) {
82 sec = sample->time.seconds;
83 depth = to_feet(sample->depth);
84 cairo_line_to(cr, SCALE(sec, depth));
87 cairo_line_to(cr, SCALE(sec, 0));
88 cairo_line_to(cr, SCALE(begins, 0));
90 cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.20);
91 cairo_fill_preserve(cr);
92 cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.80);
96 static int get_tank_pressure_range(struct dive *dive, double *scalex, double *scaley)
101 *scalex = round_seconds_up(dive->duration.seconds);
105 for (i = 0; i < dive->samples; i++) {
106 struct sample *sample = dive->sample + i;
109 if (!sample->tankpressure.mbar)
111 bar = sample->tankpressure.mbar;
123 static void plot_tank_pressure(struct dive *dive, cairo_t *cr,
124 double topx, double topy, double maxx, double maxy)
127 double scalex, scaley;
129 if (!get_tank_pressure_range(dive, &scalex, &scaley))
132 cairo_set_source_rgba(cr, 0.2, 1.0, 0.2, 0.80);
134 cairo_move_to(cr, SCALE(0, dive->beginning_pressure.mbar));
135 for (i = 1; i < dive->samples; i++) {
137 struct sample *sample = dive->sample + i;
139 sec = sample->time.seconds;
140 mbar = sample->tankpressure.mbar;
143 cairo_line_to(cr, SCALE(sec, mbar));
145 cairo_line_to(cr, SCALE(dive->duration.seconds, dive->end_pressure.mbar));
149 static void plot(cairo_t *cr, int w, int h, struct dive *dive)
151 double topx, topy, maxx, maxy;
152 double scalex, scaley;
160 plot_profile(dive, cr, topx, topy, maxx, maxy);
162 /* Tank pressure plot? */
163 plot_tank_pressure(dive, cr, topx, topy, maxx, maxy);
165 /* Bounding box last */
166 scalex = scaley = 1.0;
167 cairo_set_source_rgb(cr, 1, 1, 1);
168 cairo_move_to(cr, SCALE(0,0));
169 cairo_line_to(cr, SCALE(0,1));
170 cairo_line_to(cr, SCALE(1,1));
171 cairo_line_to(cr, SCALE(1,0));
172 cairo_close_path(cr);
177 static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
179 struct dive *dive = current_dive;
183 w = widget->allocation.width;
184 h = widget->allocation.height;
186 cr = gdk_cairo_create(widget->window);
187 cairo_set_source_rgb(cr, 0, 0, 0);
191 plot(cr, w, h, dive);
198 GtkWidget *dive_profile_frame(void)
203 frame = gtk_frame_new("Dive profile");
204 gtk_widget_show(frame);
205 da = gtk_drawing_area_new();
206 gtk_widget_set_size_request(da, 450, 350);
207 g_signal_connect(da, "expose_event", G_CALLBACK(expose_event), NULL);
208 gtk_container_add(GTK_CONTAINER(frame), da);