]> git.tdb.fi Git - ext/subsurface.git/blob - profile.c
Plot dive profile slightly more intelligently.
[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
33         topx = w / 20.0;
34         topy = h / 20.0;
35         maxx = (w - 2*topx);
36         maxy = (h - 2*topy);
37
38         cairo_set_line_width(cr, 2);
39
40         /* Get plot scaling limits */
41         maxtime = round_seconds_up(dive->duration.seconds);
42         maxdepth = round_feet_up(to_feet(dive->maxdepth));
43
44         /* Depth markers: every 15 ft */
45         scalex = 1.0;
46         scaley = maxdepth;
47         cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
48         for (i = 15; i < maxdepth; i += 15) {
49                 cairo_move_to(cr, SCALE(0, i));
50                 cairo_line_to(cr, SCALE(1, i));
51         }
52
53         /* Time markers: every 5 min */
54         scalex = maxtime;
55         scaley = 1.0;
56         for (i = 5*60; i < maxtime; i += 5*60) {
57                 cairo_move_to(cr, SCALE(i, 0));
58                 cairo_line_to(cr, SCALE(i, 1));
59         }
60         cairo_stroke(cr);
61
62         scaley = maxdepth;
63
64         /* Depth profile */
65         cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.80);
66         cairo_move_to(cr, SCALE(sample->time.seconds, to_feet(sample->depth)));
67         for (i = 1; i < dive->samples; i++) {
68                 sample++;
69                 cairo_line_to(cr, SCALE(sample->time.seconds, to_feet(sample->depth)));
70         }
71         cairo_stroke(cr);
72
73         /* Bounding box last */
74         scalex = scaley = 1.0;
75         cairo_set_source_rgb(cr, 1, 1, 1);
76         cairo_move_to(cr, SCALE(0,0));
77         cairo_line_to(cr, SCALE(0,1));
78         cairo_line_to(cr, SCALE(1,1));
79         cairo_line_to(cr, SCALE(1,0));
80         cairo_close_path(cr);
81         cairo_stroke(cr);
82
83 }
84
85 static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
86 {
87         struct dive *dive = dive_table.dives[selected_dive];
88         cairo_t *cr;
89         int w,h;
90
91         w = widget->allocation.width;
92         h = widget->allocation.height;
93
94         cr = gdk_cairo_create(widget->window);
95         cairo_set_source_rgb(cr, 0, 0, 0);
96         cairo_paint(cr);
97
98         if (dive->samples)
99                 plot(cr, w, h, dive, dive->samples, dive->sample);
100
101         cairo_destroy(cr);
102
103         return FALSE;
104 }
105
106 GtkWidget *dive_profile_frame(void)
107 {
108         GtkWidget *frame;
109         GtkWidget *da;
110
111         frame = gtk_frame_new("Dive profile");
112         gtk_widget_show(frame);
113         da = gtk_drawing_area_new();
114         gtk_widget_set_size_request(da, 450, 350);
115         g_signal_connect(da, "expose_event", G_CALLBACK(expose_event), NULL);
116         gtk_container_add(GTK_CONTAINER(frame), da);
117
118         return frame;
119 }