Project

General

Profile

Statistics
| Revision:

root / branches / simulator / projects / simulator / simulator / gui / gtk_environment_view.c @ 1049

History | View | Annotate | Download (11.7 KB)

1
#include <math.h>
2
#include <stdlib.h>
3
#include <stdio.h>
4
#include <sys/time.h>
5
#include <string.h>
6

    
7
#include <gtk/gtkmain.h>
8
#include <gtk/gtksignal.h>
9

    
10
#include "gtk_environment_view.h"
11

    
12
#include "robot.h"
13
#include "world.h"
14

    
15
#define ENVIRONMENT_VIEW_MIN_WIDTH                100
16
#define ENVIRONMENT_VIEW_MIN_HEIGHT                50
17

    
18
#define ENVIRONMENT_PI                              3.14159
19
#define ENVIRONMENT_ROBOT_DIAMETER                50
20

    
21
static GtkWidgetClass* parent_class = NULL;
22

    
23
static void gtk_environment_view_class_init(GtkEnvironmentViewClass* environmentClass);
24
static void gtk_environment_view_init(GtkEnvironmentView* view);
25
static void gtk_environment_view_destroy(GtkObject* object);
26

    
27
static void gtk_environment_view_size_request(GtkWidget* widget,
28
                GtkRequisition* req);
29
static void gtk_environment_view_realize(GtkWidget* widget);
30
static void gtk_environment_view_size_allocate(GtkWidget* widget, GtkAllocation* a);
31
static gboolean gtk_environment_view_expose(GtkWidget* widget,
32
                GdkEventExpose* event);
33

    
34
static gboolean gtk_environment_view_mouse_down(GtkWidget* widget,
35
                                GdkEventButton* event);
36
static gboolean gtk_environment_view_mouse_release(GtkWidget* widget,
37
                                GdkEventButton* event);
38
static gboolean gtk_environment_view_mouse_move(GtkWidget* widget,
39
                                GdkEventMotion* event);
40

    
41

    
42
static void draw_world(GdkDrawable* drawable, GdkGC* gc, world_t* world);
43
static void draw_robot(GdkDrawable* drawable, GdkGC* gc, 
44
                        float x, float y, float angle);
45

    
46
GtkType gtk_environment_view_get_type(void)
47
{
48
        static GtkType environment_view_type = 0;
49
        if (!environment_view_type)
50
        {
51
                static const GtkTypeInfo environment_view_info =
52
                {
53
                        "GtkEnvironmentView",
54
                        sizeof(GtkEnvironmentView),
55
                        sizeof(GtkEnvironmentViewClass),
56
                        (GtkClassInitFunc)gtk_environment_view_class_init,
57
                        (GtkObjectInitFunc)gtk_environment_view_init,
58
                        NULL, NULL, (GtkClassInitFunc)NULL
59
                };
60

    
61
                environment_view_type = gtk_type_unique(GTK_TYPE_WIDGET,
62
                        &environment_view_info);
63
        }
64

    
65
        return environment_view_type;
66
}
67

    
68
static void gtk_environment_view_class_init(GtkEnvironmentViewClass* environmentClass)
69
{
70
        GtkObjectClass* object_class;
71
        GtkWidgetClass* widget_class;
72

    
73
        object_class = (GtkObjectClass*)environmentClass;
74
        widget_class = (GtkWidgetClass*)environmentClass;
75

    
76
        parent_class = gtk_type_class(gtk_widget_get_type());
77

    
78
        object_class->destroy = gtk_environment_view_destroy;
79

    
80
        widget_class->realize = gtk_environment_view_realize;
81
        widget_class->expose_event = gtk_environment_view_expose;
82
        widget_class->size_request = gtk_environment_view_size_request;
83
        widget_class->size_allocate = gtk_environment_view_size_allocate;
84
        widget_class->button_press_event = gtk_environment_view_mouse_down;
85
        widget_class->button_release_event = gtk_environment_view_mouse_release;
86
        widget_class->motion_notify_event = gtk_environment_view_mouse_move;
87
}
88

    
89
GtkWidget* gtk_environment_view_new(void)
90
{
91
        GtkEnvironmentView* view;
92
        view = gtk_type_new(gtk_environment_view_get_type());
93

    
94
        return GTK_WIDGET(view);
95
}
96

    
97
static void gtk_environment_view_init(GtkEnvironmentView* view)
98
{
99
        view->topLeftX = -2.0;
100
        view->topLeftY = -1.3;
101
        view->scale = 2.0 / 800.0;
102
        view->width = -1;
103
        view->height = -1;
104

    
105
        GTK_WIDGET_SET_FLAGS(&(view->widget), GTK_DOUBLE_BUFFERED);
106

    
107
        view->mouseDown = 0;
108
}
109

    
110
static void gtk_environment_view_destroy(GtkObject* object)
111
{
112
        GtkEnvironmentView* view;
113
        g_return_if_fail(object != NULL);
114
        g_return_if_fail(GTK_IS_ENVIRONMENT_VIEW(object));
115

    
116
        view = GTK_ENVIRONMENT_VIEW(object);
117

    
118
        if (GTK_OBJECT_CLASS(parent_class)->destroy)
119
                (* GTK_OBJECT_CLASS(parent_class)->destroy) (object);
120
}
121

    
122
static void gtk_environment_view_realize(GtkWidget* widget)
123
{
124
        GtkEnvironmentView* view;
125
        GdkWindowAttr attributes;
126
        gint attributes_mask;
127

    
128
        g_return_if_fail( widget != NULL);
129
        g_return_if_fail( GTK_IS_ENVIRONMENT_VIEW(widget));
130

    
131
        GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
132
        view = GTK_ENVIRONMENT_VIEW(widget);
133

    
134
        attributes.x = widget->allocation.x;
135
        attributes.y = widget->allocation.y;
136
        attributes.width = widget->allocation.width;
137
        attributes.height = widget->allocation.height;
138
        attributes.wclass = GDK_INPUT_OUTPUT;
139
        attributes.window_type = GDK_WINDOW_CHILD;
140
        attributes.event_mask = gtk_widget_get_events(widget) |
141
                GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
142
                GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
143
                GDK_POINTER_MOTION_HINT_MASK;
144
        attributes.visual = gtk_widget_get_visual(widget);
145
        attributes.colormap = gtk_widget_get_colormap(widget);
146

    
147
        attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
148
        widget->window = gdk_window_new(widget->parent->window, &attributes,
149
                        attributes_mask);
150
        gdk_window_set_user_data(widget->window, widget);
151
        widget->style = gtk_style_attach(widget->style, widget->window);
152
        gtk_style_set_background(widget->style, widget->window,
153
                        GTK_STATE_NORMAL);
154
}
155

    
156
static void gtk_environment_view_size_request(GtkWidget* widget, 
157
                GtkRequisition* req)
158
{
159
        if (req->width < ENVIRONMENT_VIEW_MIN_WIDTH)
160
                req->width = ENVIRONMENT_VIEW_MIN_WIDTH;
161
        if (req->height < ENVIRONMENT_VIEW_MIN_HEIGHT)
162
                req->height = ENVIRONMENT_VIEW_MIN_HEIGHT;
163
}
164

    
165
static void gtk_environment_view_size_allocate(GtkWidget* widget, GtkAllocation* a)
166
{
167
        GtkEnvironmentView* view;
168

    
169
        g_return_if_fail(widget != NULL);
170
        g_return_if_fail(GTK_IS_ENVIRONMENT_VIEW(widget));
171
        g_return_if_fail(a != NULL);
172

    
173
        view = GTK_ENVIRONMENT_VIEW(widget);
174
        widget->allocation = *a;
175

    
176
        view->width = a->width;
177
        view->height = a->height;
178

    
179
        if (GTK_WIDGET_REALIZED(widget))
180
        {
181
                gdk_window_move_resize(widget->window, a->x, a->y, a->width, a->height);
182
        }
183
}
184

    
185
static gboolean gtk_environment_view_expose(GtkWidget* widget,
186
                GdkEventExpose* event)
187
{
188
        GtkEnvironmentView* view;
189

    
190
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
191
                return FALSE;
192
        if (event->count > 0)
193
                return FALSE;
194
        
195
        view = GTK_ENVIRONMENT_VIEW(widget);
196

    
197
        draw_world(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], &world);
198
        
199
        robot_iterator_reset();
200
        Robot* r;
201
        while ((r = robot_iterator_next()) != NULL) {
202
                draw_robot(widget->window, 
203
                        widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 
204
            r->pose.x, r->pose.y, r->pose.theta);
205
    }
206

    
207
        return FALSE;
208
}
209

    
210
static gboolean gtk_environment_view_mouse_down(GtkWidget* widget,
211
                                GdkEventButton* event)
212
{
213
        GtkEnvironmentView* view;
214

    
215
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
216
                return FALSE;
217

    
218
        view = GTK_ENVIRONMENT_VIEW(widget);
219

    
220
        if (event->button != 1)
221
                return FALSE;
222

    
223
        view->mouseDownX = event->x;
224
        view->mouseDownY = event->y;
225
        view->mouseX = event->x;
226
        view->mouseY = event->y;
227
        view->mouseDown = 1;
228

    
229
        return FALSE;
230
}
231

    
232
static gboolean gtk_environment_view_mouse_release(GtkWidget* widget,
233
                                GdkEventButton* event)
234
{
235
        GtkEnvironmentView* view;
236
        double x1, x2, y1, y2;
237
        int w, h;
238

    
239
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
240
                return FALSE;
241

    
242
        view = GTK_ENVIRONMENT_VIEW(widget);
243

    
244
        if (event->button != 1 && event->button != 3)
245
                return FALSE;
246
        
247
        if (event->button == 1)
248
                view->mouseDown = 0;
249
        view->mouseX = event->x;
250
        view->mouseY = event->y;
251
        w = abs(view->mouseX - view->mouseDownX);
252
        h = abs(view->mouseY - view->mouseDownY);
253
        
254
        // if the box is big, zoom to the box
255
        if (event->button == 1 && (w >= 10 || h >= 10))
256
        {
257
                // we need to make sure the box is to scale
258
                // scale to height
259
                if (fabs((double)w / h) <= fabs((double)view->width / view->height))
260
                {
261
                        w = (int)((double)view->width / view->height * h);
262
                        if (view->mouseX < view->mouseDownX)
263
                                view->mouseX = view->mouseDownX - w;
264
                        else
265
                                view->mouseX = view->mouseDownX + w;
266
                }
267
                // scale to width
268
                else
269
                {
270
                        h = (int)((double)view->height / view->width * w);
271
                        if (view->mouseY < view->mouseDownY)
272
                                view->mouseY = view->mouseDownY - h;
273
                        else
274
                                view->mouseY = view->mouseDownY + h;
275
                }
276
        
277
                x1 = view->mouseX * view->scale + view->topLeftX;
278
                y1 = view->mouseY * view->scale + view->topLeftY;
279
                x2 = view->mouseDownX * view->scale + view->topLeftX;
280
                y2 = view->mouseDownY * view->scale + view->topLeftY;
281
                if (x2 < x1)
282
                        x1 = x2;
283
                if (y2 < y1)
284
                        y1 = y2;
285

    
286
                view->scale = (w * view->scale) / view->width;
287
                view->topLeftX = x1;
288
                view->topLeftY = y1;
289
        }
290
        else
291
        {
292
                x1 = view->mouseX * view->scale + view->topLeftX;
293
                y1 = view->mouseY * view->scale + view->topLeftY;
294

    
295
                // zoom in on left click, out on right click
296
                if (event->button == 1)
297
                        view->scale /= 2.0;
298
                else
299
                        view->scale *= 2.0;
300
                view->topLeftX = x1 - view->width / 2 * view->scale;
301
                view->topLeftY = y1 - view->height / 2 * view->scale;
302
        }
303

    
304
        return FALSE;
305
}
306

    
307
static gboolean gtk_environment_view_mouse_move(GtkWidget* widget,
308
                                GdkEventMotion* event)
309
{
310
        GtkEnvironmentView* view;
311

    
312
        if (widget == NULL || !GTK_IS_ENVIRONMENT_VIEW(widget) || event == NULL)
313
                return FALSE;
314

    
315
        view = GTK_ENVIRONMENT_VIEW(widget);
316

    
317
        view->mouseX = event->x;
318
        view->mouseY = event->y;
319

    
320
        if (!view->mouseDown)
321
                return FALSE;
322

    
323
        // we need to make sure the new view is to scale
324
        int w = abs(view->mouseX - view->mouseDownX);
325
        int h = abs(view->mouseY - view->mouseDownY);
326
        // scale to height
327
        if (fabs((double)w / h) <= fabs((double)view->width / view->height))
328
        {
329
                w = (int)((double)view->width / view->height * h);
330
                if (view->mouseX < view->mouseDownX)
331
                        view->mouseX = view->mouseDownX - w;
332
                else
333
                        view->mouseX = view->mouseDownX + w;
334
        }
335
        // scale to width
336
        else
337
        {
338
                h = (int)((double)view->height / view->width * w);
339
                if (view->mouseY < view->mouseDownY)
340
                        view->mouseY = view->mouseDownY - h;
341
                else
342
                        view->mouseY = view->mouseDownY + h;
343
        }
344

    
345
        gtk_widget_queue_draw_area(widget, 0, 0, view->width, view->height);
346

    
347
        return FALSE;
348
}
349

    
350
void gtk_environment_view_refresh(GtkWidget* view)
351
{
352
        gdk_threads_enter();
353
        gtk_widget_queue_draw(view);
354
        gdk_threads_leave();
355
}
356

    
357
static void draw_world(GdkDrawable* drawable, GdkGC* gc, world_t* world)
358
{
359
        int i, j;
360
        GdkPoint* points;
361
        poly_t* p;
362

    
363
        if (!drawable || !gc || !world)
364
                return;
365

    
366
        double leftx = world->win.p1.x;
367
        double upy = world->win.p1.x;
368
        double xwidth = world->win.p2.x - leftx;
369
        double yheight = world->win.p2.y - upy;
370
        int width, height;
371
        gdk_drawable_get_size(drawable, &width, &height);
372
        if (xwidth / width < yheight / height)
373
                width = (int)(height / yheight * xwidth);
374
        else
375
                height = (int)(width / xwidth * yheight);
376

    
377
        for (i = 0 ; i < world->max_objs; i++)
378
        {
379
                object_t* o = &(world->objs[i]);
380
                switch (o->id)
381
                {
382
                        case ID_POLY:
383
                                p = (poly_t*)o->props;
384
                                points = (GdkPoint*)malloc(sizeof(GdkPoint) * p->num_pts);
385
                                for (j = 0; j < p->num_pts; j++)
386
                                {
387
                                        points[j].x = (int)((p->pts[j].x - leftx) / xwidth * width);
388
                                        points[j].y = (int)((p->pts[j].y - upy) / yheight * height);
389
                                }
390
                                switch(p->type)
391
                                {
392
                                        case POLY_CONNECTED:
393
                                                gdk_draw_polygon(drawable, gc, 1, points, p->num_pts);
394
                                                break;
395
                                        default:
396
                                                fprintf(stderr, "Detected unexpected type of polygon.\n");
397
                                                break;
398
                                }
399
                                free(points);
400
                                break;
401
                        // no object
402
                        case ID_NULL:
403
                                break;
404
                        default:
405
                                fprintf(stderr, "Unexpected object type %d in world.\n", o->id);
406
                                break;
407
                }
408
        }
409
}
410

    
411
static void draw_robot(GdkDrawable* drawable, GdkGC* gc, 
412
                        float x, float y, float angle)
413
{
414
        if (!drawable || !gc)
415
                return;
416

    
417
        double leftx = world.win.p1.x;
418
        double upy = world.win.p1.x;
419
        double xwidth = world.win.p2.x - leftx;
420
        double yheight = world.win.p2.y - upy;
421
        int width, height;
422
        gdk_drawable_get_size(drawable, &width, &height);
423
        if (xwidth / width < yheight / height)
424
                width = (int)(height / yheight * xwidth);
425
        else
426
                height = (int)(width / xwidth * yheight);
427

    
428
        x = ((x - leftx) / xwidth * width);
429
        y = ((y - upy) / yheight * height);
430
        int x_c = (int)x - ENVIRONMENT_ROBOT_DIAMETER / 2;
431
        int y_c = (int)y - ENVIRONMENT_ROBOT_DIAMETER / 2;
432

    
433
        gdk_draw_arc(drawable, gc, FALSE, x_c, y_c, 
434
                  ENVIRONMENT_ROBOT_DIAMETER, ENVIRONMENT_ROBOT_DIAMETER, 
435
        0, 360*64);
436

    
437
        //TODO: scale radius
438
        gdk_draw_line(drawable, gc, x, y, 
439
                x + (ENVIRONMENT_ROBOT_DIAMETER - 10) * cos(-angle),
440
                y - (ENVIRONMENT_ROBOT_DIAMETER - 10) * sin(-angle));
441
}
442