5 #include <gdk/gdkkeysyms.h>
8 typedef struct _point {
14 typedef struct _line {
17 typedef struct _trapezoid {
21 typedef struct _traps {
22 struct _traps *next, *prev;
29 typedef struct _edge {
35 typedef struct _edges {
36 struct _edges *next, *prev;
43 typedef struct _TrapView {
46 struct _TrapView *group_head;
47 struct _TrapView *group_next;
48 struct _TrapView *group_prev;
50 cairo_surface_t *pixmap;
51 int pixmap_width, pixmap_height;
54 traps_t *current_traps;
57 edges_t *current_edges;
65 gint mag_drag_x, mag_drag_y;
68 typedef struct _TrapViewClass {
69 GtkWidgetClass parent_class;
72 G_DEFINE_TYPE (TrapView, trap_view, GTK_TYPE_WIDGET)
75 _compute_intersection_x_for_y (const line_t *line,
78 gdouble dx = line->p2.x - line->p1.x;
79 gdouble dy = line->p2.y - line->p1.y;
89 x += (y - line->p1.y)*dx/dy;
94 _compute_intersection_point (const line_t *line,
98 p->x = _compute_intersection_x_for_y (line, p->y = y);
101 static cairo_surface_t *
102 pixmap_create (TrapView *self, cairo_surface_t *target)
104 cairo_surface_t *surface = cairo_surface_create_similar (target, CAIRO_CONTENT_COLOR,
105 self->widget.allocation.width,
106 self->widget.allocation.height);
110 gdouble sf_x, sf_y, sf;
113 double dash[2] = {8, 8};
114 double dots[2] = {0., 1.};
119 traps = self->current_traps;
122 edges = self->current_edges;
124 extents = traps->extents;
126 if (edges->extents.p1.x < extents.p1.x)
127 extents.p1.x = edges->extents.p1.x;
128 if (edges->extents.p1.y < extents.p1.y)
129 extents.p1.y = edges->extents.p1.y;
130 if (edges->extents.p2.x > extents.p2.x)
131 extents.p2.x = edges->extents.p2.x;
132 if (edges->extents.p2.y > extents.p2.y)
133 extents.p2.y = edges->extents.p2.y;
136 mid = (extents.p2.x + extents.p1.x) / 2.;
137 dim = (extents.p2.x - extents.p1.x) / 2. * 1.25;
138 sf_x = self->widget.allocation.width / dim / 2;
140 mid = (extents.p2.y + extents.p1.y) / 2.;
141 dim = (extents.p2.y - extents.p1.y) / 2. * 1.25;
142 sf_y = self->widget.allocation.height / dim / 2;
144 sf = MIN (sf_x, sf_y);
146 mid = (extents.p2.x + extents.p1.x) / 2.;
147 dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25;
149 mid = (extents.p2.y + extents.p1.y) / 2.;
150 dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25;
153 cr = cairo_create (surface);
154 cairo_set_source_rgb (cr, 1, 1, 1);
158 cairo_scale (cr, sf, sf);
159 cairo_translate (cr, -x0, -y0);
160 cairo_set_source_rgba (cr, 0, 1, 0, .2);
161 for (n = 0; n < traps->num_traps; n++) {
162 const trapezoid_t *t = &traps->traps[n];
164 _compute_intersection_point (&t->left, t->top, &p);
165 cairo_move_to (cr, p.x, p.y);
166 _compute_intersection_point (&t->right, t->top, &p);
167 cairo_line_to (cr, p.x, p.y);
168 _compute_intersection_point (&t->right, t->bottom, &p);
169 cairo_line_to (cr, p.x, p.y);
170 _compute_intersection_point (&t->left, t->bottom, &p);
171 cairo_line_to (cr, p.x, p.y);
172 cairo_close_path (cr);
183 cairo_matrix_init_scale (&m, sf, sf);
184 cairo_matrix_translate (&m, -x0, -y0);
186 cairo_set_line_width (cr, 1.);
187 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
188 for (n = 0; n < traps->num_traps; n++) {
189 const trapezoid_t *t = &traps->traps[n];
191 _compute_intersection_point (&t->left, t->top, &p);
192 cairo_matrix_transform_point (&m, &p.x, &p.y);
193 cairo_move_to (cr, floor (p.x), floor (p.y) + .5);
194 cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1]));
196 _compute_intersection_point (&t->right, t->top, &p);
197 cairo_matrix_transform_point (&m, &p.x, &p.y);
198 cairo_line_to (cr, ceil (p.x), floor (p.y) + .5);
201 _compute_intersection_point (&t->left, t->bottom, &p);
202 cairo_matrix_transform_point (&m, &p.x, &p.y);
203 cairo_move_to (cr, floor (p.x), floor (p.y) + .5);
204 cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1]));
206 _compute_intersection_point (&t->right, t->bottom, &p);
207 cairo_matrix_transform_point (&m, &p.x, &p.y);
208 cairo_line_to (cr, ceil (p.x), floor (p.y) + .5);
211 } cairo_restore (cr);
216 cairo_scale (cr, sf, sf);
217 cairo_translate (cr, -x0, -y0);
219 for (n = 0; n < traps->num_traps; n++) {
220 const trapezoid_t *t = &traps->traps[n];
221 cairo_move_to (cr, t->left.p1.x, t->left.p1.y);
222 cairo_line_to (cr, t->left.p2.x, t->left.p2.y);
224 } cairo_restore (cr);
225 cairo_set_source_rgb (cr, 1, 0, 0);
226 cairo_set_line_width (cr, 1.);
227 cairo_set_dash (cr, dash, 2, 0.);
229 } cairo_restore (cr);
234 cairo_scale (cr, sf, sf);
235 cairo_translate (cr, -x0, -y0);
237 for (n = 0; n < traps->num_traps; n++) {
238 const trapezoid_t *t = &traps->traps[n];
239 _compute_intersection_point (&t->left, t->top, &p);
240 cairo_move_to (cr, p.x, p.y);
241 _compute_intersection_point (&t->left, t->bottom, &p);
242 cairo_line_to (cr, p.x, p.y);
244 } cairo_restore (cr);
245 cairo_set_source_rgb (cr, 1, 0, 0);
247 } cairo_restore (cr);
252 cairo_scale (cr, sf, sf);
253 cairo_translate (cr, -x0, -y0);
255 for (n = 0; n < traps->num_traps; n++) {
256 const trapezoid_t *t = &traps->traps[n];
257 cairo_move_to (cr, t->right.p1.x, t->right.p1.y);
258 cairo_line_to (cr, t->right.p2.x, t->right.p2.y);
260 } cairo_restore (cr);
261 cairo_set_source_rgb (cr, 0, 0, 1);
262 cairo_set_line_width (cr, 1.);
263 cairo_set_dash (cr, dash, 2, 0.);
265 } cairo_restore (cr);
270 cairo_scale (cr, sf, sf);
271 cairo_translate (cr, -x0, -y0);
273 for (n = 0; n < traps->num_traps; n++) {
274 const trapezoid_t *t = &traps->traps[n];
275 _compute_intersection_point (&t->right, t->top, &p);
276 cairo_move_to (cr, p.x, p.y);
277 _compute_intersection_point (&t->right, t->bottom, &p);
278 cairo_line_to (cr, p.x, p.y);
279 } cairo_restore (cr);
280 cairo_set_source_rgb (cr, 0, 0, 1);
282 } cairo_restore (cr);
288 cairo_scale (cr, sf, sf);
289 cairo_translate (cr, -x0, -y0);
291 for (n = 0; n < traps->num_traps; n++) {
292 const trapezoid_t *t = &traps->traps[n];
293 _compute_intersection_point (&t->left, t->top, &p);
294 cairo_move_to (cr, p.x, p.y);
295 cairo_close_path (cr);
296 _compute_intersection_point (&t->left, t->bottom, &p);
297 cairo_move_to (cr, p.x, p.y);
298 cairo_close_path (cr);
299 _compute_intersection_point (&t->right, t->top, &p);
300 cairo_move_to (cr, p.x, p.y);
301 cairo_close_path (cr);
302 _compute_intersection_point (&t->right, t->bottom, &p);
303 cairo_move_to (cr, p.x, p.y);
304 cairo_close_path (cr);
306 } cairo_restore (cr);
307 cairo_set_source_rgb (cr, 0, 0, 0);
308 cairo_set_dash (cr, dots, 2, 0.);
309 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
310 cairo_set_line_width (cr, 4.);
312 } cairo_restore (cr);
318 for (n = 0; n < edges->num_edges; n++) {
319 const edge_t *e = &edges->edges[n];
322 cairo_scale (cr, sf, sf);
323 cairo_translate (cr, -x0, -y0);
324 cairo_move_to (cr, e->p1.x, e->p1.y);
325 cairo_line_to (cr, e->p2.x, e->p2.y);
326 } cairo_restore (cr);
329 cairo_set_source_rgb (cr, 0, 0, 1);
330 cairo_set_dash (cr, dash, 2, dash[0]);
332 cairo_set_source_rgb (cr, 1, 0, 0);
333 cairo_set_dash (cr, dash, 2, 0.);
336 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
337 cairo_set_line_width (cr, 1.);
341 cairo_scale (cr, sf, sf);
342 cairo_translate (cr, -x0, -y0);
343 cairo_move_to (cr, e->p1.x, e->p1.y);
344 cairo_close_path (cr);
345 cairo_move_to (cr, e->p2.x, e->p2.y);
346 cairo_close_path (cr);
347 } cairo_restore (cr);
348 cairo_set_source_rgb (cr, 0, 0, 0);
349 cairo_set_dash (cr, dots, 2, 0.);
350 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
351 cairo_set_line_width (cr, 4.);
363 trap_view_draw (TrapView *self, cairo_t *cr)
367 gdouble sf_x, sf_y, sf;
370 double dash[2] = {8, 8};
375 if (self->pixmap_width != self->widget.allocation.width ||
376 self->pixmap_height != self->widget.allocation.height)
378 cairo_surface_destroy (self->pixmap);
379 self->pixmap = pixmap_create (self, cairo_get_target (cr));
380 self->pixmap_width = self->widget.allocation.width;
381 self->pixmap_height = self->widget.allocation.height;
385 cairo_set_source_surface (cr, self->pixmap, 0, 0);
389 traps = self->current_traps;
393 extents = traps->extents;
394 edges = self->current_edges;
396 if (edges->extents.p1.x < extents.p1.x)
397 extents.p1.x = edges->extents.p1.x;
398 if (edges->extents.p1.y < extents.p1.y)
399 extents.p1.y = edges->extents.p1.y;
400 if (edges->extents.p2.x > extents.p2.x)
401 extents.p2.x = edges->extents.p2.x;
402 if (edges->extents.p2.y > extents.p2.y)
403 extents.p2.y = edges->extents.p2.y;
406 mid = (extents.p2.x + extents.p1.x) / 2.;
407 dim = (extents.p2.x - extents.p1.x) / 2. * 1.25;
408 sf_x = self->widget.allocation.width / dim / 2;
410 mid = (extents.p2.y + extents.p1.y) / 2.;
411 dim = (extents.p2.y - extents.p1.y) / 2. * 1.25;
412 sf_y = self->widget.allocation.height / dim / 2;
414 sf = MIN (sf_x, sf_y);
416 mid = (extents.p2.x + extents.p1.x) / 2.;
417 dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25;
419 mid = (extents.p2.y + extents.p1.y) / 2.;
420 dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25;
425 /* draw a zoom view of the area around the mouse */
427 double zoom = self->mag_zoom;
428 int size = self->mag_size;
433 cairo_rectangle (cr, self->mag_x, self->mag_y, size, size);
434 cairo_stroke_preserve (cr);
435 cairo_set_source_rgb (cr, 1, 1, 1);
436 cairo_fill_preserve (cr);
439 /* compute roi in extents */
440 cairo_translate (cr, self->mag_x + size/2, self->mag_y + size/2);
443 cairo_scale (cr, zoom, zoom);
444 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
445 for (n = 0; n < traps->num_traps; n++) {
446 const trapezoid_t *t = &traps->traps[n];
448 _compute_intersection_point (&t->left, t->top, &p);
449 cairo_move_to (cr, p.x, p.y);
450 _compute_intersection_point (&t->right, t->top, &p);
451 cairo_line_to (cr, p.x, p.y);
452 _compute_intersection_point (&t->right, t->bottom, &p);
453 cairo_line_to (cr, p.x, p.y);
454 _compute_intersection_point (&t->left, t->bottom, &p);
455 cairo_line_to (cr, p.x, p.y);
456 cairo_close_path (cr);
457 cairo_set_source_rgba (cr, 0, 1, 0, .2);
464 cairo_matrix_init_scale (&m, zoom, zoom);
465 cairo_matrix_translate (&m, -(self->px / sf + x0), -(self->py /sf + y0));
467 cairo_set_source_rgb (cr, 0, 0, 0);
468 cairo_set_line_width (cr, 1.);
469 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
470 for (n = 0; n < traps->num_traps; n++) {
471 const trapezoid_t *t = &traps->traps[n];
473 _compute_intersection_point (&t->left, t->top, &p);
474 cairo_matrix_transform_point (&m, &p.x, &p.y);
475 cairo_move_to (cr, floor (p.x), floor (p.y) + .5);
476 cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1]));
478 _compute_intersection_point (&t->right, t->top, &p);
479 cairo_matrix_transform_point (&m, &p.x, &p.y);
480 cairo_line_to (cr, ceil (p.x), floor (p.y) + .5);
483 _compute_intersection_point (&t->left, t->bottom, &p);
484 cairo_matrix_transform_point (&m, &p.x, &p.y);
485 cairo_move_to (cr, floor (p.x), floor (p.y) + .5);
486 cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1]));
488 _compute_intersection_point (&t->right, t->bottom, &p);
489 cairo_matrix_transform_point (&m, &p.x, &p.y);
490 cairo_line_to (cr, ceil (p.x), floor (p.y) + .5);
493 } cairo_restore (cr);
495 cairo_save (cr); { /* left extents */
497 cairo_scale (cr, zoom, zoom);
498 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
499 for (n = 0; n < traps->num_traps; n++) {
500 const trapezoid_t *t = &traps->traps[n];
501 cairo_move_to (cr, t->left.p1.x, t->left.p1.y);
502 cairo_line_to (cr, t->left.p2.x, t->left.p2.y);
504 } cairo_restore (cr);
505 cairo_set_source_rgb (cr, 1, 0, 0);
506 cairo_set_line_width (cr, .5);
507 cairo_set_dash (cr, dash, 2, 0.);
509 } cairo_restore (cr);
510 cairo_save (cr); { /* right extents */
512 cairo_scale (cr, zoom, zoom);
513 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
515 for (n = 0; n < traps->num_traps; n++) {
516 const trapezoid_t *t = &traps->traps[n];
517 cairo_move_to (cr, t->right.p1.x, t->right.p1.y);
518 cairo_line_to (cr, t->right.p2.x, t->right.p2.y);
520 } cairo_restore (cr);
521 cairo_set_source_rgb (cr, 0, 0, 1);
522 cairo_set_line_width (cr, .5);
523 cairo_set_dash (cr, dash, 2, 0.);
525 } cairo_restore (cr);
527 cairo_save (cr); { /* left lines */
529 cairo_scale (cr, zoom, zoom);
530 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
531 for (n = 0; n < traps->num_traps; n++) {
532 const trapezoid_t *t = &traps->traps[n];
533 _compute_intersection_point (&t->left, t->top, &p);
534 cairo_move_to (cr, p.x, p.y);
535 _compute_intersection_point (&t->left, t->bottom, &p);
536 cairo_line_to (cr, p.x, p.y);
539 cairo_set_source_rgb (cr, 1, 0, 0);
541 } cairo_restore (cr);
542 cairo_save (cr); { /* right lines */
544 cairo_scale (cr, zoom, zoom);
545 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
546 for (n = 0; n < traps->num_traps; n++) {
547 const trapezoid_t *t = &traps->traps[n];
548 _compute_intersection_point (&t->right, t->top, &p);
549 cairo_move_to (cr, p.x, p.y);
550 _compute_intersection_point (&t->right, t->bottom, &p);
551 cairo_line_to (cr, p.x, p.y);
554 cairo_set_source_rgb (cr, 0, 0, 1);
556 } cairo_restore (cr);
560 double dots[2] = {0., 1.};
563 cairo_scale (cr, zoom, zoom);
564 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
565 for (n = 0; n < traps->num_traps; n++) {
566 const trapezoid_t *t = &traps->traps[n];
567 _compute_intersection_point (&t->left, t->top, &p);
568 cairo_move_to (cr, p.x, p.y);
569 cairo_close_path (cr);
570 _compute_intersection_point (&t->left, t->bottom, &p);
571 cairo_move_to (cr, p.x, p.y);
572 cairo_close_path (cr);
573 _compute_intersection_point (&t->right, t->top, &p);
574 cairo_move_to (cr, p.x, p.y);
575 cairo_close_path (cr);
576 _compute_intersection_point (&t->right, t->bottom, &p);
577 cairo_move_to (cr, p.x, p.y);
578 cairo_close_path (cr);
581 cairo_set_source_rgb (cr, 0, 0, 0);
582 cairo_set_dash (cr, dots, 2, 0.);
583 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
584 cairo_set_line_width (cr, 4.);
586 } cairo_restore (cr);
593 -zoom*fmod (self->px/sf + x0, 1.),
594 -zoom*fmod (self->py/sf + y0, 1.));
595 for (i = -size/2/zoom - 1; i <= size/2/zoom + 1; i++) {
596 cairo_move_to (cr, zoom*i, -size/2);
597 cairo_line_to (cr, zoom*i, size/2 + zoom);
598 cairo_move_to (cr, -size/2, zoom*i);
599 cairo_line_to (cr, size/2 + zoom, zoom*i);
601 cairo_set_source_rgba (cr, .7, .7, .7, .5);
602 cairo_set_line_width (cr, 1.);
604 } cairo_restore (cr);
611 trapezoid_area (const trapezoid_t *t)
613 gdouble inner_left, inner_right;
614 gdouble outer_left, outer_right;
618 /* split into 3 sections: a rectangle with a pair of triangular bookends */
619 inner_left = _compute_intersection_x_for_y (&t->left, t->top);
620 outer_left = _compute_intersection_x_for_y (&t->left, t->bottom);
621 if (outer_left > inner_left) {
622 gdouble t = outer_left;
623 outer_left = inner_left;
627 inner_right = _compute_intersection_x_for_y (&t->right, t->top);
628 outer_right = _compute_intersection_x_for_y (&t->right, t->bottom);
629 if (outer_right > inner_right) {
630 gdouble t = outer_right;
631 outer_right = inner_right;
635 if (outer_left > outer_right) { /* reverse */
639 outer_left = inner_right;
643 inner_left = outer_right;
647 height = t->bottom - t->top;
648 area = (inner_left - outer_left) * height / 2;
649 area += (outer_right - inner_right) * height / 2;
650 area += (inner_right - inner_left) * height;
656 traps_compute_total_area (const traps_t *traps)
660 for (n = 0; n < traps->num_traps; n++)
661 area += trapezoid_area (&traps->traps[n]);
666 trap_view_draw_labels (TrapView *self, cairo_t *cr)
674 traps = self->current_traps;
678 /* convert total area from fixed-point (assuming 24.8) */
679 total_area = traps_compute_total_area (traps) / (256. * 256.);
680 str = g_strdup_printf ("Number of trapezoids:\t%d\n"
681 "Total area of trapezoids:\t%.2f",
684 layout = gtk_widget_create_pango_layout (&self->widget, str);
687 pango_layout_get_pixel_size (layout, &width, &height);
689 cairo_move_to (cr, 10, 10 + height);
690 pango_cairo_show_layout (cr, layout);
691 g_object_unref (layout);
695 trap_view_expose (GtkWidget *w, GdkEventExpose *ev)
697 TrapView *self = (TrapView *) w;
700 cr = gdk_cairo_create (w->window);
701 gdk_cairo_region (cr, ev->region);
704 trap_view_draw (self, cr);
705 trap_view_draw_labels (self, cr);
712 trap_view_advance (TrapView *self)
714 if (self->current_traps && self->current_traps->prev)
715 self->current_traps = self->current_traps->prev;
716 if (self->current_edges && self->current_edges->prev)
717 self->current_edges = self->current_edges->prev;
718 self->pixmap_width = self->pixmap_height = 0;
719 gtk_widget_queue_draw (&self->widget);
723 trap_view_back (TrapView *self)
725 if (self->current_traps && self->current_traps->next)
726 self->current_traps = self->current_traps->next;
727 if (self->current_edges && self->current_edges->next)
728 self->current_edges = self->current_edges->next;
729 self->pixmap_width = self->pixmap_height = 0;
730 gtk_widget_queue_draw (&self->widget);
734 trap_view_group_foreach (TrapView *group, GFunc func, gpointer data)
738 group = group->group_next;
743 trap_view_key_press (GtkWidget *w, GdkEventKey *ev)
745 TrapView *self = (TrapView *) w;
747 switch (ev->keyval) {
749 trap_view_group_foreach (self->group_head,
750 (GFunc) trap_view_back,
755 trap_view_group_foreach (self->group_head,
756 (GFunc) trap_view_advance,
761 trap_view_group_foreach (self->group_head,
762 (GFunc) trap_view_advance,
776 trap_view_button_press (GtkWidget *w, GdkEventButton *ev)
778 TrapView *self = (TrapView *) w;
780 if (ev->x < self->mag_x ||
781 ev->y < self->mag_y ||
782 ev->x > self->mag_x + self->mag_size ||
783 ev->y > self->mag_y + self->mag_size)
785 if (ev->type == GDK_BUTTON_PRESS) {
786 if (self->current_traps == NULL)
789 if (ev->button == 1) {
790 trap_view_group_foreach (self->group_head,
791 (GFunc) trap_view_advance,
793 } else if (ev->button == 3) {
794 trap_view_group_foreach (self->group_head,
795 (GFunc) trap_view_back,
802 self->in_mag_drag = TRUE;
803 self->mag_drag_x = ev->x;
804 self->mag_drag_y = ev->y;
811 trap_view_button_release (GtkWidget *w, GdkEventButton *ev)
813 TrapView *self = (TrapView *) w;
815 self->in_mag_drag = FALSE;
821 trap_view_update_mouse (TrapView *self, GdkEventMotion *ev)
826 gtk_widget_queue_draw (&self->widget);
830 trap_view_update_magnifier (TrapView *self, gint *xy)
835 gtk_widget_queue_draw (&self->widget);
839 trap_view_motion (GtkWidget *w, GdkEventMotion *ev)
841 TrapView *self = (TrapView *) w;
843 if (self->in_mag_drag) {
846 xy[0] = self->mag_x + ev->x - self->mag_drag_x;
847 xy[1] = self->mag_y + ev->y - self->mag_drag_y;
849 trap_view_group_foreach (self->group_head,
850 (GFunc) trap_view_update_magnifier,
853 self->mag_drag_x = ev->x;
854 self->mag_drag_y = ev->y;
855 } else if (ev->x < self->mag_x ||
856 ev->y < self->mag_y ||
857 ev->x > self->mag_x + self->mag_size ||
858 ev->y > self->mag_y + self->mag_size)
860 trap_view_group_foreach (self->group_head,
861 (GFunc) trap_view_update_mouse,
869 trap_view_realize (GtkWidget *widget)
871 GdkWindowAttr attributes;
873 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
875 attributes.window_type = GDK_WINDOW_CHILD;
876 attributes.x = widget->allocation.x;
877 attributes.y = widget->allocation.y;
878 attributes.width = widget->allocation.width;
879 attributes.height = widget->allocation.height;
880 attributes.wclass = GDK_INPUT_OUTPUT;
881 attributes.visual = gtk_widget_get_visual (widget);
882 attributes.colormap = gtk_widget_get_colormap (widget);
883 attributes.event_mask = gtk_widget_get_events (widget) |
884 GDK_BUTTON_PRESS_MASK |
885 GDK_BUTTON_RELEASE_MASK |
887 GDK_KEY_RELEASE_MASK |
888 GDK_POINTER_MOTION_MASK |
889 GDK_BUTTON_MOTION_MASK |
892 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
894 GDK_WA_X | GDK_WA_Y |
895 GDK_WA_VISUAL | GDK_WA_COLORMAP);
896 gdk_window_set_user_data (widget->window, widget);
898 widget->style = gtk_style_attach (widget->style, widget->window);
899 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
903 trap_view_size_allocate (GtkWidget *w, GdkRectangle *r)
905 TrapView *self = (TrapView *) w;
907 GTK_WIDGET_CLASS (trap_view_parent_class)->size_allocate (w, r);
909 self->mag_x = w->allocation.width - self->mag_size - 10;
910 self->mag_y = w->allocation.height - self->mag_size - 10;
914 trap_view_finalize (GObject *obj)
916 G_OBJECT_CLASS (trap_view_parent_class)->finalize (obj);
920 trap_view_class_init (TrapViewClass *klass)
922 GObjectClass *object_class = (GObjectClass *) klass;
923 GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
925 object_class->finalize = trap_view_finalize;
927 widget_class->realize = trap_view_realize;
928 widget_class->size_allocate = trap_view_size_allocate;
929 widget_class->expose_event = trap_view_expose;
930 widget_class->key_press_event = trap_view_key_press;
931 widget_class->button_press_event = trap_view_button_press;
932 widget_class->button_release_event = trap_view_button_release;
933 widget_class->motion_notify_event = trap_view_motion;
937 trap_view_init (TrapView *self)
940 self->mag_size = 200;
942 GTK_WIDGET_SET_FLAGS (self, GTK_CAN_FOCUS);
946 _traps_add_trapezoid (TrapView *tv, traps_t *traps, const trapezoid_t *trap)
948 if (trap->top < traps->extents.p1.y)
949 traps->extents.p1.y = trap->top;
950 if (trap->bottom > traps->extents.p2.y)
951 traps->extents.p2.y = trap->bottom;
953 if (trap->left.p1.x < traps->extents.p1.x)
954 traps->extents.p1.x = trap->left.p1.x;
955 if (trap->left.p2.x < traps->extents.p1.x)
956 traps->extents.p1.x = trap->left.p2.x;
958 if (trap->right.p1.x > traps->extents.p2.x)
959 traps->extents.p2.x = trap->right.p1.x;
960 if (trap->right.p2.x > traps->extents.p2.x)
961 traps->extents.p2.x = trap->right.p2.x;
963 if (traps->num_traps == traps->size) {
964 int newsize = 2 * traps->size;
967 newtraps = g_realloc (traps,
968 sizeof (traps_t) + newsize * sizeof (trapezoid_t));
969 if (newtraps == NULL)
972 if (tv->current_traps == traps)
973 tv->current_traps = newtraps;
976 traps->size = newsize;
978 if (traps->next != NULL)
979 traps->next->prev = newtraps;
980 if (traps->prev != NULL)
981 traps->prev->next = newtraps;
983 tv->traps_list = newtraps;
986 traps->traps[traps->num_traps++] = *trap;
992 traps_new (TrapView *tv)
996 t = g_malloc (sizeof (traps_t) + 16 * sizeof (trapezoid_t));
998 t->next = tv->traps_list;
1000 tv->traps_list->prev = t;
1003 if (tv->current_traps == NULL)
1004 tv->current_traps = t;
1008 t->extents.p1.x = G_MAXDOUBLE;
1009 t->extents.p1.y = G_MAXDOUBLE;
1010 t->extents.p2.x = -G_MAXDOUBLE;
1011 t->extents.p2.y = -G_MAXDOUBLE;
1017 _edges_add_edge (TrapView *tv, edges_t *edges, edge_t *e)
1019 if (e->top < edges->extents.p1.y)
1020 edges->extents.p1.y = e->top;
1021 if (e->bottom > edges->extents.p2.y)
1022 edges->extents.p2.y = e->bottom;
1024 _compute_intersection_point (&e->line, e->top, &e->p1);
1025 _compute_intersection_point (&e->line, e->bottom, &e->p2);
1027 if (e->p1.x < edges->extents.p1.x)
1028 edges->extents.p1.x = e->p1.x;
1029 if (e->p2.x < edges->extents.p1.x)
1030 edges->extents.p1.x = e->p2.x;
1032 if (e->p1.x > edges->extents.p2.x)
1033 edges->extents.p2.x = e->p1.x;
1034 if (e->p2.x > edges->extents.p2.x)
1035 edges->extents.p2.x = e->p2.x;
1037 if (edges->num_edges == edges->size) {
1038 int newsize = 2 * edges->size;
1041 newedges = g_realloc (edges,
1042 sizeof (edges_t) + newsize * sizeof (edge_t));
1043 if (newedges == NULL)
1046 if (tv->current_edges == edges)
1047 tv->current_edges = newedges;
1050 edges->size = newsize;
1052 if (edges->next != NULL)
1053 edges->next->prev = newedges;
1054 if (edges->prev != NULL)
1055 edges->prev->next = newedges;
1057 tv->edges_list = newedges;
1060 edges->edges[edges->num_edges++] = *e;
1066 edges_new (TrapView *tv)
1070 t = g_malloc (sizeof (edges_t) + 16 * sizeof (edge_t));
1072 t->next = tv->edges_list;
1074 tv->edges_list->prev = t;
1077 if (tv->current_edges == NULL)
1078 tv->current_edges = t;
1082 t->extents.p1.x = G_MAXDOUBLE;
1083 t->extents.p1.y = G_MAXDOUBLE;
1084 t->extents.p2.x = -G_MAXDOUBLE;
1085 t->extents.p2.y = -G_MAXDOUBLE;
1091 main (int argc, char **argv)
1093 TrapView *tv, *group_head = NULL, *group_prev = NULL;
1094 GtkWidget *window, *hbox;
1097 gtk_init (&argc, &argv);
1099 hbox = gtk_hbox_new (TRUE, 0);
1101 file = fopen (argv[1], "r");
1107 tv = g_object_new (trap_view_get_type (), NULL);
1108 gtk_box_pack_start (GTK_BOX (hbox), &tv->widget, TRUE, TRUE, 0);
1109 gtk_widget_show (&tv->widget);
1111 tv->group_prev = group_prev;
1112 tv->group_next = NULL;
1114 group_prev->group_next = tv;
1116 if (group_head == NULL)
1118 tv->group_head = group_head;
1120 traps = traps_new (tv);
1121 while (getline (&line, &len, file) != -1) {
1125 "%lf %lf L:(%lf, %lf), (%lf, %lf) R:(%lf, %lf), (%lf, %lf)",
1127 &t.left.p1.x, &t.left.p1.y,
1128 &t.left.p2.x, &t.left.p2.y,
1129 &t.right.p1.x, &t.right.p1.y,
1130 &t.right.p2.x, &t.right.p2.y) == 10) {
1131 traps = _traps_add_trapezoid (tv, traps, &t);
1133 if (traps->num_traps) {
1134 g_print ("read %d trapezoids\n", traps->num_traps);
1135 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1136 traps->extents.p1.x, traps->extents.p1.y,
1137 traps->extents.p2.x, traps->extents.p2.y);
1138 traps = traps_new (tv);
1145 if (traps->num_traps) {
1146 g_print ("read %d trapezoids\n", traps->num_traps);
1147 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1148 traps->extents.p1.x, traps->extents.p1.y,
1149 traps->extents.p2.x, traps->extents.p2.y);
1153 file = fopen (argv[2], "r");
1159 tv = g_object_new (trap_view_get_type (), NULL);
1160 gtk_box_pack_start (GTK_BOX (hbox), &tv->widget, TRUE, TRUE, 0);
1161 gtk_widget_show (&tv->widget);
1163 tv->group_prev = group_prev;
1164 tv->group_next = NULL;
1166 group_prev->group_next = tv;
1168 if (group_head == NULL)
1170 tv->group_head = group_head;
1172 traps = traps_new (tv);
1173 while (getline (&line, &len, file) != -1) {
1177 "%lf %lf L:(%lf, %lf), (%lf, %lf) R:(%lf, %lf), (%lf, %lf)",
1179 &t.left.p1.x, &t.left.p1.y,
1180 &t.left.p2.x, &t.left.p2.y,
1181 &t.right.p1.x, &t.right.p1.y,
1182 &t.right.p2.x, &t.right.p2.y) == 10) {
1183 traps = _traps_add_trapezoid (tv, traps, &t);
1185 if (traps->num_traps) {
1186 g_print ("read %d trapezoids\n", traps->num_traps);
1187 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1188 traps->extents.p1.x, traps->extents.p1.y,
1189 traps->extents.p2.x, traps->extents.p2.y);
1190 traps = traps_new (tv);
1197 if (traps->num_traps) {
1198 g_print ("read %d trapezoids\n", traps->num_traps);
1199 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1200 traps->extents.p1.x, traps->extents.p1.y,
1201 traps->extents.p2.x, traps->extents.p2.y);
1207 file = fopen (argv[3], "r");
1213 edges = edges_new (tv);
1214 while (getline (&line, &len, file) != -1) {
1218 "(%lf, %lf), (%lf, %lf) %lf %lf %d",
1219 &e.line.p1.x, &e.line.p1.y,
1220 &e.line.p2.x, &e.line.p2.y,
1223 edges = _edges_add_edge (tv, edges, &e);
1225 if (edges->num_edges) {
1226 g_print ("read %d edges\n", edges->num_edges);
1227 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1228 edges->extents.p1.x, edges->extents.p1.y,
1229 edges->extents.p2.x, edges->extents.p2.y);
1230 edges = edges_new (tv);
1237 if (edges->num_edges) {
1238 g_print ("read %d edges\n", edges->num_edges);
1239 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1240 edges->extents.p1.x, edges->extents.p1.y,
1241 edges->extents.p2.x, edges->extents.p2.y);
1247 file = fopen (argv[3], "r");
1253 tv = g_object_new (trap_view_get_type (), NULL);
1254 gtk_box_pack_start (GTK_BOX (hbox), &tv->widget, TRUE, TRUE, 0);
1255 gtk_widget_show (&tv->widget);
1257 tv->group_prev = group_prev;
1258 tv->group_next = NULL;
1260 group_prev->group_next = tv;
1262 if (group_head == NULL)
1264 tv->group_head = group_head;
1266 traps = traps_new (tv);
1267 while (getline (&line, &len, file) != -1) {
1271 "%lf %lf L:(%lf, %lf), (%lf, %lf) R:(%lf, %lf), (%lf, %lf)",
1273 &t.left.p1.x, &t.left.p1.y,
1274 &t.left.p2.x, &t.left.p2.y,
1275 &t.right.p1.x, &t.right.p1.y,
1276 &t.right.p2.x, &t.right.p2.y) == 10) {
1277 traps = _traps_add_trapezoid (tv, traps, &t);
1279 if (traps->num_traps) {
1280 g_print ("read %d trapezoids\n", traps->num_traps);
1281 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1282 traps->extents.p1.x, traps->extents.p1.y,
1283 traps->extents.p2.x, traps->extents.p2.y);
1284 traps = traps_new (tv);
1291 if (traps->num_traps) {
1292 g_print ("read %d trapezoids\n", traps->num_traps);
1293 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1294 traps->extents.p1.x, traps->extents.p1.y,
1295 traps->extents.p2.x, traps->extents.p2.y);
1301 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1302 g_signal_connect (window, "delete-event",
1303 G_CALLBACK (gtk_main_quit), NULL);
1304 gtk_widget_set_size_request (window, 512, 512);
1305 gtk_container_add (GTK_CONTAINER (window), hbox);
1306 gtk_widget_show (hbox);
1307 gtk_widget_show (window);