]> git.tdb.fi Git - ext/subsurface.git/blob - profile.c
plot a fancier 'filled' depth profile
[ext/subsurface.git] / profile.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h>
4
5 #include "dive.h"
6 #include "display.h"
7
8 int selected_dive = 0;
9
10 #define ROUND_UP(x,y) ((((x)+(y)-1)/(y))*(y))
11 #define MAX(x,y) ((x) > (y) ? (x) : (y))
12
13 static int round_seconds_up(int seconds)
14 {
15         return MAX(30, ROUND_UP(seconds, 60*10));
16 }
17
18 static int round_feet_up(int feet)
19 {
20         return MAX(45, ROUND_UP(feet+5, 15));
21 }
22
23 /* Scale to 0,0 -> maxx,maxy */
24 #define SCALE(x,y) (x)*maxx/scalex+topx,(y)*maxy/scaley+topy
25
26 static void plot(cairo_t *cr, int w, int h, struct dive *dive, int samples, struct sample *sample)
27 {
28         int i;
29         double topx, topy, maxx, maxy;
30         double scalex, scaley;
31         int maxtime, maxdepth;
32         int begins, sec, depth;
33
34         topx = w / 20.0;
35         topy = h / 20.0;
36         maxx = (w - 2*topx);
37         maxy = (h - 2*topy);
38
39         cairo_set_line_width(cr, 2);
40
41         /* Get plot scaling limits */
42         maxtime = round_seconds_up(dive->duration.seconds);
43         maxdepth = round_feet_up(to_feet(dive->maxdepth));
44
45         /* Depth markers: every 15 ft */
46         scalex = 1.0;
47         scaley = maxdepth;
48         cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
49         for (i = 15; i < maxdepth; i += 15) {
50                 cairo_move_to(cr, SCALE(0, i));
51                 cairo_line_to(cr, SCALE(1, i));
52         }
53
54         /* Time markers: every 5 min */
55         scalex = maxtime;
56         scaley = 1.0;
57         for (i = 5*60; i < maxtime; i += 5*60) {
58                 cairo_move_to(cr, SCALE(i, 0));
59                 cairo_line_to(cr, SCALE(i, 1));
60         }
61         cairo_stroke(cr);
62
63         scaley = maxdepth;
64
65         /* Depth profile */
66         cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.80);
67         begins = sample->time.seconds;
68         cairo_move_to(cr, SCALE(sample->time.seconds, to_feet(sample->depth)));
69         for (i = 1; i < dive->samples; i++) {
70                 sample++;
71                 sec = sample->time.seconds;
72                 depth = to_feet(sample->depth);
73                 cairo_line_to(cr, SCALE(sec, depth));
74         }
75         scaley = 1.0;
76         cairo_line_to(cr, SCALE(sec, 0));
77         cairo_line_to(cr, SCALE(begins, 0));
78         cairo_close_path(cr);
79         cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.20);
80         cairo_fill_preserve(cr);
81         cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.80);
82         cairo_stroke(cr);
83
84         /* Bounding box last */
85         scalex = scaley = 1.0;
86         cairo_set_source_rgb(cr, 1, 1, 1);
87         cairo_move_to(cr, SCALE(0,0));
88         cairo_line_to(cr, SCALE(0,1));
89         cairo_line_to(cr, SCALE(1,1));
90         cairo_line_to(cr, SCALE(1,0));
91         cairo_close_path(cr);
92         cairo_stroke(cr);
93
94 }
95
96 static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
97 {
98         struct dive *dive = dive_table.dives[selected_dive];
99         cairo_t *cr;
100         int w,h;
101
102         w = widget->allocation.width;
103         h = widget->allocation.height;
104
105         cr = gdk_cairo_create(widget->window);
106         cairo_set_source_rgb(cr, 0, 0, 0);
107         cairo_paint(cr);
108
109         if (dive->samples)
110                 plot(cr, w, h, dive, dive->samples, dive->sample);
111
112         cairo_destroy(cr);
113
114         return FALSE;
115 }
116
117 GtkWidget *dive_profile_frame(void)
118 {
119         GtkWidget *frame;
120         GtkWidget *da;
121
122         frame = gtk_frame_new("Dive profile");
123         gtk_widget_show(frame);
124         da = gtk_drawing_area_new();
125         gtk_widget_set_size_request(da, 450, 350);
126         g_signal_connect(da, "expose_event", G_CALLBACK(expose_event), NULL);
127         gtk_container_add(GTK_CONTAINER(frame), da);
128
129         return frame;
130 }