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;
51 traps_t *current_traps;
54 edges_t *current_edges;
62 gint mag_drag_x, mag_drag_y;
65 typedef struct _TrapViewClass {
66 GtkWidgetClass parent_class;
69 G_DEFINE_TYPE (TrapView, trap_view, GTK_TYPE_WIDGET)
72 _compute_intersection_x_for_y (const line_t *line,
75 gdouble dx = line->p2.x - line->p1.x;
76 gdouble dy = line->p2.y - line->p1.y;
86 x += (y - line->p1.y)*dx/dy;
91 _compute_intersection_point (const line_t *line,
95 p->x = _compute_intersection_x_for_y (line, p->y = y);
99 trap_view_draw (TrapView *self, cairo_t *cr)
103 gdouble sf_x, sf_y, sf;
105 gdouble x0, x1, y0, y1;
106 double dash[2] = {8, 8};
107 double dots[2] = {0., 1.};
114 cairo_set_source_rgb (cr, 1, 1, 1);
118 traps = self->current_traps;
119 edges = self->current_edges;
120 if (traps == NULL && edges == NULL)
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 extents = edges->extents;
138 mid = (extents.p2.x + extents.p1.x) / 2.;
139 dim = (extents.p2.x - extents.p1.x) / 2. * 1.25;
140 sf_x = self->widget.allocation.width / dim / 2;
142 mid = (extents.p2.y + extents.p1.y) / 2.;
143 dim = (extents.p2.y - extents.p1.y) / 2. * 1.25;
144 sf_y = self->widget.allocation.height / dim / 2;
146 sf = MIN (sf_x, sf_y);
148 mid = (extents.p2.x + extents.p1.x) / 2.;
149 dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25;
152 mid = (extents.p2.y + extents.p1.y) / 2.;
153 dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25;
159 cairo_scale (cr, sf, sf);
160 cairo_translate (cr, -x0, -y0);
161 cairo_set_source_rgba (cr, 0, 1, 0, .2);
162 for (n = 0; n < traps->num_traps; n++) {
163 const trapezoid_t *t = &traps->traps[n];
165 _compute_intersection_point (&t->left, t->top, &p);
166 cairo_move_to (cr, p.x, p.y);
167 _compute_intersection_point (&t->right, t->top, &p);
168 cairo_line_to (cr, p.x, p.y);
169 _compute_intersection_point (&t->right, t->bottom, &p);
170 cairo_line_to (cr, p.x, p.y);
171 _compute_intersection_point (&t->left, t->bottom, &p);
172 cairo_line_to (cr, p.x, p.y);
173 cairo_close_path (cr);
185 cairo_matrix_init_scale (&m, sf, sf);
186 cairo_matrix_translate (&m, -x0, -y0);
188 cairo_set_line_width (cr, 1.);
189 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
190 for (n = 0; n < traps->num_traps; n++) {
191 const trapezoid_t *t = &traps->traps[n];
193 _compute_intersection_point (&t->left, t->top, &p);
194 cairo_matrix_transform_point (&m, &p.x, &p.y);
195 cairo_move_to (cr, floor (p.x), floor (p.y) + .5);
196 cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1]));
198 _compute_intersection_point (&t->right, t->top, &p);
199 cairo_matrix_transform_point (&m, &p.x, &p.y);
200 cairo_line_to (cr, ceil (p.x), floor (p.y) + .5);
203 _compute_intersection_point (&t->left, t->bottom, &p);
204 cairo_matrix_transform_point (&m, &p.x, &p.y);
205 cairo_move_to (cr, floor (p.x), floor (p.y) + .5);
206 cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1]));
208 _compute_intersection_point (&t->right, t->bottom, &p);
209 cairo_matrix_transform_point (&m, &p.x, &p.y);
210 cairo_line_to (cr, ceil (p.x), floor (p.y) + .5);
213 } cairo_restore (cr);
218 cairo_scale (cr, sf, sf);
219 cairo_translate (cr, -x0, -y0);
221 for (n = 0; n < traps->num_traps; n++) {
222 const trapezoid_t *t = &traps->traps[n];
223 cairo_move_to (cr, t->left.p1.x, t->left.p1.y);
224 cairo_line_to (cr, t->left.p2.x, t->left.p2.y);
226 } cairo_restore (cr);
227 cairo_set_source_rgb (cr, 1, 0, 0);
228 cairo_set_line_width (cr, 1.);
229 cairo_set_dash (cr, dash, 2, 0.);
231 } cairo_restore (cr);
236 cairo_scale (cr, sf, sf);
237 cairo_translate (cr, -x0, -y0);
239 for (n = 0; n < traps->num_traps; n++) {
240 const trapezoid_t *t = &traps->traps[n];
241 _compute_intersection_point (&t->left, t->top, &p);
242 cairo_move_to (cr, p.x, p.y);
243 _compute_intersection_point (&t->left, t->bottom, &p);
244 cairo_line_to (cr, p.x, p.y);
246 } cairo_restore (cr);
247 cairo_set_source_rgb (cr, 1, 0, 0);
249 } cairo_restore (cr);
254 cairo_scale (cr, sf, sf);
255 cairo_translate (cr, -x0, -y0);
257 for (n = 0; n < traps->num_traps; n++) {
258 const trapezoid_t *t = &traps->traps[n];
259 cairo_move_to (cr, t->right.p1.x, t->right.p1.y);
260 cairo_line_to (cr, t->right.p2.x, t->right.p2.y);
262 } cairo_restore (cr);
263 cairo_set_source_rgb (cr, 0, 0, 1);
264 cairo_set_line_width (cr, 1.);
265 cairo_set_dash (cr, dash, 2, 0.);
267 } cairo_restore (cr);
272 cairo_scale (cr, sf, sf);
273 cairo_translate (cr, -x0, -y0);
275 for (n = 0; n < traps->num_traps; n++) {
276 const trapezoid_t *t = &traps->traps[n];
277 _compute_intersection_point (&t->right, t->top, &p);
278 cairo_move_to (cr, p.x, p.y);
279 _compute_intersection_point (&t->right, t->bottom, &p);
280 cairo_line_to (cr, p.x, p.y);
281 } cairo_restore (cr);
282 cairo_set_source_rgb (cr, 0, 0, 1);
284 } cairo_restore (cr);
290 cairo_scale (cr, sf, sf);
291 cairo_translate (cr, -x0, -y0);
293 for (n = 0; n < traps->num_traps; n++) {
294 const trapezoid_t *t = &traps->traps[n];
295 _compute_intersection_point (&t->left, t->top, &p);
296 cairo_move_to (cr, p.x, p.y);
297 cairo_close_path (cr);
298 _compute_intersection_point (&t->left, t->bottom, &p);
299 cairo_move_to (cr, p.x, p.y);
300 cairo_close_path (cr);
301 _compute_intersection_point (&t->right, t->top, &p);
302 cairo_move_to (cr, p.x, p.y);
303 cairo_close_path (cr);
304 _compute_intersection_point (&t->right, t->bottom, &p);
305 cairo_move_to (cr, p.x, p.y);
306 cairo_close_path (cr);
308 } cairo_restore (cr);
309 cairo_set_source_rgb (cr, 0, 0, 0);
310 cairo_set_dash (cr, dots, 2, 0.);
311 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
312 cairo_set_line_width (cr, 4.);
314 } cairo_restore (cr);
320 for (n = 0; n < edges->num_edges; n++) {
321 const edge_t *e = &edges->edges[n];
324 cairo_scale (cr, sf, sf);
325 cairo_translate (cr, -x0, -y0);
326 cairo_move_to (cr, e->p1.x, e->p1.y);
327 cairo_line_to (cr, e->p2.x, e->p2.y);
328 } cairo_restore (cr);
331 cairo_set_source_rgb (cr, 0, 0, 1);
332 cairo_set_dash (cr, dash, 2, dash[0]);
334 cairo_set_source_rgb (cr, 1, 0, 0);
335 cairo_set_dash (cr, dash, 2, 0.);
338 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
339 cairo_set_line_width (cr, 1.);
343 cairo_scale (cr, sf, sf);
344 cairo_translate (cr, -x0, -y0);
345 cairo_move_to (cr, e->p1.x, e->p1.y);
346 cairo_close_path (cr);
347 cairo_move_to (cr, e->p2.x, e->p2.y);
348 cairo_close_path (cr);
349 } cairo_restore (cr);
350 cairo_set_source_rgb (cr, 0, 0, 0);
351 cairo_set_dash (cr, dots, 2, 0.);
352 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
353 cairo_set_line_width (cr, 4.);
360 /* draw a zoom view of the area around the mouse */
363 double zoom = self->mag_zoom;
364 int size = self->mag_size;
367 cairo_rectangle (cr, self->mag_x, self->mag_y, size, size);
368 cairo_stroke_preserve (cr);
369 cairo_set_source_rgb (cr, 1, 1, 1);
370 cairo_fill_preserve (cr);
373 /* compute roi in extents */
374 cairo_translate (cr, self->mag_x + size/2, self->mag_y + size/2);
378 cairo_scale (cr, zoom, zoom);
379 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
380 for (n = 0; n < traps->num_traps; n++) {
381 const trapezoid_t *t = &traps->traps[n];
383 _compute_intersection_point (&t->left, t->top, &p);
384 cairo_move_to (cr, p.x, p.y);
385 _compute_intersection_point (&t->right, t->top, &p);
386 cairo_line_to (cr, p.x, p.y);
387 _compute_intersection_point (&t->right, t->bottom, &p);
388 cairo_line_to (cr, p.x, p.y);
389 _compute_intersection_point (&t->left, t->bottom, &p);
390 cairo_line_to (cr, p.x, p.y);
391 cairo_close_path (cr);
392 cairo_set_source_rgba (cr, 0, 1, 0, .2);
401 cairo_matrix_init_scale (&m, zoom, zoom);
402 cairo_matrix_translate (&m, -(self->px / sf + x0), -(self->py /sf + y0));
404 cairo_set_source_rgb (cr, 0, 0, 0);
405 cairo_set_line_width (cr, 1.);
406 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
407 for (n = 0; n < traps->num_traps; n++) {
408 const trapezoid_t *t = &traps->traps[n];
410 _compute_intersection_point (&t->left, t->top, &p);
411 cairo_matrix_transform_point (&m, &p.x, &p.y);
412 cairo_move_to (cr, floor (p.x), floor (p.y) + .5);
413 cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1]));
415 _compute_intersection_point (&t->right, t->top, &p);
416 cairo_matrix_transform_point (&m, &p.x, &p.y);
417 cairo_line_to (cr, ceil (p.x), floor (p.y) + .5);
420 _compute_intersection_point (&t->left, t->bottom, &p);
421 cairo_matrix_transform_point (&m, &p.x, &p.y);
422 cairo_move_to (cr, floor (p.x), floor (p.y) + .5);
423 cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1]));
425 _compute_intersection_point (&t->right, t->bottom, &p);
426 cairo_matrix_transform_point (&m, &p.x, &p.y);
427 cairo_line_to (cr, ceil (p.x), floor (p.y) + .5);
430 } cairo_restore (cr);
432 cairo_save (cr); { /* left extents */
434 cairo_scale (cr, zoom, zoom);
435 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
436 for (n = 0; n < traps->num_traps; n++) {
437 const trapezoid_t *t = &traps->traps[n];
438 cairo_move_to (cr, t->left.p1.x, t->left.p1.y);
439 cairo_line_to (cr, t->left.p2.x, t->left.p2.y);
441 } cairo_restore (cr);
442 cairo_set_source_rgb (cr, 1, 0, 0);
443 cairo_set_line_width (cr, .5);
444 cairo_set_dash (cr, dash, 2, 0.);
446 } cairo_restore (cr);
447 cairo_save (cr); { /* right extents */
449 cairo_scale (cr, zoom, zoom);
450 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
452 for (n = 0; n < traps->num_traps; n++) {
453 const trapezoid_t *t = &traps->traps[n];
454 cairo_move_to (cr, t->right.p1.x, t->right.p1.y);
455 cairo_line_to (cr, t->right.p2.x, t->right.p2.y);
457 } cairo_restore (cr);
458 cairo_set_source_rgb (cr, 0, 0, 1);
459 cairo_set_line_width (cr, .5);
460 cairo_set_dash (cr, dash, 2, 0.);
462 } cairo_restore (cr);
464 cairo_save (cr); { /* left lines */
466 cairo_scale (cr, zoom, zoom);
467 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
468 for (n = 0; n < traps->num_traps; n++) {
469 const trapezoid_t *t = &traps->traps[n];
470 _compute_intersection_point (&t->left, t->top, &p);
471 cairo_move_to (cr, p.x, p.y);
472 _compute_intersection_point (&t->left, t->bottom, &p);
473 cairo_line_to (cr, p.x, p.y);
476 cairo_set_source_rgb (cr, 1, 0, 0);
478 } cairo_restore (cr);
479 cairo_save (cr); { /* right lines */
481 cairo_scale (cr, zoom, zoom);
482 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
483 for (n = 0; n < traps->num_traps; n++) {
484 const trapezoid_t *t = &traps->traps[n];
485 _compute_intersection_point (&t->right, t->top, &p);
486 cairo_move_to (cr, p.x, p.y);
487 _compute_intersection_point (&t->right, t->bottom, &p);
488 cairo_line_to (cr, p.x, p.y);
491 cairo_set_source_rgb (cr, 0, 0, 1);
493 } cairo_restore (cr);
497 double dots[2] = {0., 1.};
500 cairo_scale (cr, zoom, zoom);
501 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
502 for (n = 0; n < traps->num_traps; n++) {
503 const trapezoid_t *t = &traps->traps[n];
504 _compute_intersection_point (&t->left, t->top, &p);
505 cairo_move_to (cr, p.x, p.y);
506 cairo_close_path (cr);
507 _compute_intersection_point (&t->left, t->bottom, &p);
508 cairo_move_to (cr, p.x, p.y);
509 cairo_close_path (cr);
510 _compute_intersection_point (&t->right, t->top, &p);
511 cairo_move_to (cr, p.x, p.y);
512 cairo_close_path (cr);
513 _compute_intersection_point (&t->right, t->bottom, &p);
514 cairo_move_to (cr, p.x, p.y);
515 cairo_close_path (cr);
518 cairo_set_source_rgb (cr, 0, 0, 0);
519 cairo_set_dash (cr, dots, 2, 0.);
520 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
521 cairo_set_line_width (cr, 4.);
523 } cairo_restore (cr);
527 for (n = 0; n < edges->num_edges; n++) {
528 const edge_t *e = &edges->edges[n];
531 cairo_scale (cr, zoom, zoom);
532 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
533 cairo_move_to (cr, e->p1.x, e->p1.y);
534 cairo_line_to (cr, e->p2.x, e->p2.y);
535 } cairo_restore (cr);
538 cairo_set_source_rgb (cr, 0, 0, 1);
539 cairo_set_dash (cr, dash, 2, dash[0]);
541 cairo_set_source_rgb (cr, 1, 0, 0);
542 cairo_set_dash (cr, dash, 2, 0.);
545 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
546 cairo_set_line_width (cr, 1.);
550 cairo_scale (cr, zoom, zoom);
551 cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0));
552 cairo_move_to (cr, e->p1.x, e->p1.y);
553 cairo_close_path (cr);
554 cairo_move_to (cr, e->p2.x, e->p2.y);
555 cairo_close_path (cr);
556 } cairo_restore (cr);
557 cairo_set_source_rgb (cr, 0, 0, 0);
558 cairo_set_dash (cr, dots, 2, 0.);
559 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
560 cairo_set_line_width (cr, 4.);
572 -zoom*fmod (self->px/sf + x0, 1.),
573 -zoom*fmod (self->py/sf + y0, 1.));
574 for (i = -size/2/zoom - 1; i <= size/2/zoom + 1; i++) {
575 cairo_move_to (cr, zoom*i, -size/2);
576 cairo_line_to (cr, zoom*i, size/2 + zoom);
577 cairo_move_to (cr, -size/2, zoom*i);
578 cairo_line_to (cr, size/2 + zoom, zoom*i);
580 cairo_set_source_rgba (cr, .7, .7, .7, .5);
581 cairo_set_line_width (cr, 1.);
583 } cairo_restore (cr);
591 edge_length (const edge_t *e)
593 return hypot (e->p2.x - e->p1.x, e->p2.y - e->p1.y);
597 edges_compute_total_length (const edges_t *edges)
601 for (n = 0; n < edges->num_edges; n++)
602 len += edge_length (&edges->edges[n]);
607 trapezoid_area (const trapezoid_t *t)
609 gdouble inner_left, inner_right;
610 gdouble outer_left, outer_right;
614 /* split into 3 sections: a rectangle with a pair of triangular bookends */
615 inner_left = _compute_intersection_x_for_y (&t->left, t->top);
616 outer_left = _compute_intersection_x_for_y (&t->left, t->bottom);
617 if (outer_left > inner_left) {
618 gdouble t = outer_left;
619 outer_left = inner_left;
623 inner_right = _compute_intersection_x_for_y (&t->right, t->top);
624 outer_right = _compute_intersection_x_for_y (&t->right, t->bottom);
625 if (outer_right > inner_right) {
626 gdouble t = outer_right;
627 outer_right = inner_right;
631 if (outer_left > outer_right) { /* reverse */
635 outer_left = inner_right;
639 inner_left = outer_right;
643 height = t->bottom - t->top;
644 area = (inner_left - outer_left) * height / 2;
645 area += (outer_right - inner_right) * height / 2;
646 area += (inner_right - inner_left) * height;
652 traps_compute_total_area (const traps_t *traps)
656 for (n = 0; n < traps->num_traps; n++)
657 area += trapezoid_area (&traps->traps[n]);
662 trap_view_draw_labels (TrapView *self, cairo_t *cr)
671 string = g_string_new (NULL);
673 traps = self->current_traps;
675 /* convert total area from fixed-point (assuming 24.8) */
676 gdouble total_area = traps_compute_total_area (traps) / (256. * 256.);
677 g_string_append_printf (string,
678 "Number of trapezoids:\t%d\n"
679 "Total area of trapezoids:\t%.2f\n",
684 edges = self->current_edges;
686 double total_length = edges_compute_total_length (edges) / 256.;
687 g_string_append_printf (string,
688 "Number of edges:\t%d\n"
689 "Total length of edges: \t%.2f\n",
694 str = g_string_free (string, FALSE);
695 layout = gtk_widget_create_pango_layout (&self->widget, str);
698 pango_layout_get_pixel_size (layout, &width, &height);
700 cairo_move_to (cr, 10, 40);
701 pango_cairo_show_layout (cr, layout);
702 g_object_unref (layout);
706 trap_view_expose (GtkWidget *w, GdkEventExpose *ev)
708 TrapView *self = (TrapView *) w;
711 cr = gdk_cairo_create (w->window);
712 gdk_cairo_region (cr, ev->region);
715 trap_view_draw (self, cr);
716 trap_view_draw_labels (self, cr);
723 trap_view_advance (TrapView *self)
725 if (self->current_traps && self->current_traps->prev)
726 self->current_traps = self->current_traps->prev;
727 if (self->current_edges && self->current_edges->prev)
728 self->current_edges = self->current_edges->prev;
729 gtk_widget_queue_draw (&self->widget);
733 trap_view_back (TrapView *self)
735 if (self->current_traps && self->current_traps->next)
736 self->current_traps = self->current_traps->next;
737 if (self->current_edges && self->current_edges->next)
738 self->current_edges = self->current_edges->next;
739 gtk_widget_queue_draw (&self->widget);
743 trap_view_group_foreach (TrapView *group, GFunc func, gpointer data)
747 group = group->group_next;
752 trap_view_key_press (GtkWidget *w, GdkEventKey *ev)
754 TrapView *self = (TrapView *) w;
756 switch (ev->keyval) {
758 trap_view_group_foreach (self->group_head,
759 (GFunc) trap_view_back,
764 trap_view_group_foreach (self->group_head,
765 (GFunc) trap_view_advance,
770 trap_view_group_foreach (self->group_head,
771 (GFunc) trap_view_advance,
785 trap_view_button_press (GtkWidget *w, GdkEventButton *ev)
787 TrapView *self = (TrapView *) w;
789 if (ev->x < self->mag_x ||
790 ev->y < self->mag_y ||
791 ev->x > self->mag_x + self->mag_size ||
792 ev->y > self->mag_y + self->mag_size)
794 if (ev->type == GDK_BUTTON_PRESS) {
795 if (self->current_traps == NULL)
798 if (ev->button == 1) {
799 trap_view_group_foreach (self->group_head,
800 (GFunc) trap_view_advance,
802 } else if (ev->button == 3) {
803 trap_view_group_foreach (self->group_head,
804 (GFunc) trap_view_back,
811 self->in_mag_drag = TRUE;
812 self->mag_drag_x = ev->x;
813 self->mag_drag_y = ev->y;
820 trap_view_button_release (GtkWidget *w, GdkEventButton *ev)
822 TrapView *self = (TrapView *) w;
824 self->in_mag_drag = FALSE;
830 trap_view_update_mouse (TrapView *self, GdkEventMotion *ev)
835 gtk_widget_queue_draw (&self->widget);
839 trap_view_update_magnifier (TrapView *self, gint *xy)
844 gtk_widget_queue_draw (&self->widget);
848 trap_view_motion (GtkWidget *w, GdkEventMotion *ev)
850 TrapView *self = (TrapView *) w;
852 if (self->in_mag_drag) {
855 xy[0] = self->mag_x + ev->x - self->mag_drag_x;
856 xy[1] = self->mag_y + ev->y - self->mag_drag_y;
858 trap_view_group_foreach (self->group_head,
859 (GFunc) trap_view_update_magnifier,
862 self->mag_drag_x = ev->x;
863 self->mag_drag_y = ev->y;
864 } else if (ev->x < self->mag_x ||
865 ev->y < self->mag_y ||
866 ev->x > self->mag_x + self->mag_size ||
867 ev->y > self->mag_y + self->mag_size)
869 trap_view_group_foreach (self->group_head,
870 (GFunc) trap_view_update_mouse,
878 trap_view_realize (GtkWidget *widget)
880 GdkWindowAttr attributes;
882 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
884 attributes.window_type = GDK_WINDOW_CHILD;
885 attributes.x = widget->allocation.x;
886 attributes.y = widget->allocation.y;
887 attributes.width = widget->allocation.width;
888 attributes.height = widget->allocation.height;
889 attributes.wclass = GDK_INPUT_OUTPUT;
890 attributes.visual = gtk_widget_get_visual (widget);
891 attributes.colormap = gtk_widget_get_colormap (widget);
892 attributes.event_mask = gtk_widget_get_events (widget) |
893 GDK_BUTTON_PRESS_MASK |
894 GDK_BUTTON_RELEASE_MASK |
896 GDK_KEY_RELEASE_MASK |
897 GDK_POINTER_MOTION_MASK |
898 GDK_BUTTON_MOTION_MASK |
901 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
903 GDK_WA_X | GDK_WA_Y |
904 GDK_WA_VISUAL | GDK_WA_COLORMAP);
905 gdk_window_set_user_data (widget->window, widget);
907 widget->style = gtk_style_attach (widget->style, widget->window);
908 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
912 trap_view_size_allocate (GtkWidget *w, GdkRectangle *r)
914 TrapView *self = (TrapView *) w;
916 GTK_WIDGET_CLASS (trap_view_parent_class)->size_allocate (w, r);
918 self->mag_x = w->allocation.width - self->mag_size - 10;
919 self->mag_y = w->allocation.height - self->mag_size - 10;
923 trap_view_finalize (GObject *obj)
925 G_OBJECT_CLASS (trap_view_parent_class)->finalize (obj);
929 trap_view_class_init (TrapViewClass *klass)
931 GObjectClass *object_class = (GObjectClass *) klass;
932 GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
934 object_class->finalize = trap_view_finalize;
936 widget_class->realize = trap_view_realize;
937 widget_class->size_allocate = trap_view_size_allocate;
938 widget_class->expose_event = trap_view_expose;
939 widget_class->key_press_event = trap_view_key_press;
940 widget_class->button_press_event = trap_view_button_press;
941 widget_class->button_release_event = trap_view_button_release;
942 widget_class->motion_notify_event = trap_view_motion;
946 trap_view_init (TrapView *self)
949 self->mag_size = 200;
951 GTK_WIDGET_SET_FLAGS (self, GTK_CAN_FOCUS);
955 _traps_add_trapezoid (TrapView *tv, traps_t *traps, const trapezoid_t *trap)
957 if (trap->top < traps->extents.p1.y)
958 traps->extents.p1.y = trap->top;
959 if (trap->bottom > traps->extents.p2.y)
960 traps->extents.p2.y = trap->bottom;
962 if (trap->left.p1.x < traps->extents.p1.x)
963 traps->extents.p1.x = trap->left.p1.x;
964 if (trap->left.p2.x < traps->extents.p1.x)
965 traps->extents.p1.x = trap->left.p2.x;
967 if (trap->right.p1.x > traps->extents.p2.x)
968 traps->extents.p2.x = trap->right.p1.x;
969 if (trap->right.p2.x > traps->extents.p2.x)
970 traps->extents.p2.x = trap->right.p2.x;
972 if (traps->num_traps == traps->size) {
973 int newsize = 2 * traps->size;
976 newtraps = g_realloc (traps,
977 sizeof (traps_t) + newsize * sizeof (trapezoid_t));
978 if (newtraps == NULL)
981 if (tv->current_traps == traps)
982 tv->current_traps = newtraps;
985 traps->size = newsize;
987 if (traps->next != NULL)
988 traps->next->prev = newtraps;
989 if (traps->prev != NULL)
990 traps->prev->next = newtraps;
992 tv->traps_list = newtraps;
995 traps->traps[traps->num_traps++] = *trap;
1001 traps_new (TrapView *tv)
1005 t = g_malloc (sizeof (traps_t) + 16 * sizeof (trapezoid_t));
1007 t->next = tv->traps_list;
1009 tv->traps_list->prev = t;
1012 if (tv->current_traps == NULL)
1013 tv->current_traps = t;
1017 t->extents.p1.x = G_MAXDOUBLE;
1018 t->extents.p1.y = G_MAXDOUBLE;
1019 t->extents.p2.x = -G_MAXDOUBLE;
1020 t->extents.p2.y = -G_MAXDOUBLE;
1026 _edges_add_edge (TrapView *tv, edges_t *edges, edge_t *e)
1028 if (e->top < edges->extents.p1.y)
1029 edges->extents.p1.y = e->top;
1030 if (e->bottom > edges->extents.p2.y)
1031 edges->extents.p2.y = e->bottom;
1033 _compute_intersection_point (&e->line, e->top, &e->p1);
1034 _compute_intersection_point (&e->line, e->bottom, &e->p2);
1036 if (e->p1.x < edges->extents.p1.x)
1037 edges->extents.p1.x = e->p1.x;
1038 if (e->p2.x < edges->extents.p1.x)
1039 edges->extents.p1.x = e->p2.x;
1041 if (e->p1.x > edges->extents.p2.x)
1042 edges->extents.p2.x = e->p1.x;
1043 if (e->p2.x > edges->extents.p2.x)
1044 edges->extents.p2.x = e->p2.x;
1046 if (edges->num_edges == edges->size) {
1047 int newsize = 2 * edges->size;
1050 newedges = g_realloc (edges,
1051 sizeof (edges_t) + newsize * sizeof (edge_t));
1052 if (newedges == NULL)
1055 if (tv->current_edges == edges)
1056 tv->current_edges = newedges;
1059 edges->size = newsize;
1061 if (edges->next != NULL)
1062 edges->next->prev = newedges;
1063 if (edges->prev != NULL)
1064 edges->prev->next = newedges;
1066 tv->edges_list = newedges;
1069 edges->edges[edges->num_edges++] = *e;
1075 edges_new (TrapView *tv)
1079 t = g_malloc (sizeof (edges_t) + 16 * sizeof (edge_t));
1081 t->next = tv->edges_list;
1083 tv->edges_list->prev = t;
1086 if (tv->current_edges == NULL)
1087 tv->current_edges = t;
1091 t->extents.p1.x = G_MAXDOUBLE;
1092 t->extents.p1.y = G_MAXDOUBLE;
1093 t->extents.p2.x = -G_MAXDOUBLE;
1094 t->extents.p2.y = -G_MAXDOUBLE;
1100 main (int argc, char **argv)
1102 TrapView *tv, *tv2, *group_head = NULL, *group_prev = NULL;
1105 GtkWidget *window, *hbox;
1110 gtk_init (&argc, &argv);
1112 hbox = gtk_hbox_new (TRUE, 0);
1114 tv = g_object_new (trap_view_get_type (), NULL);
1115 gtk_box_pack_start (GTK_BOX (hbox), &tv->widget, TRUE, TRUE, 0);
1116 gtk_widget_show (&tv->widget);
1118 tv->group_prev = group_prev;
1119 tv->group_next = NULL;
1121 group_prev->group_next = tv;
1123 if (group_head == NULL)
1125 tv->group_head = group_head;
1127 file = fopen (argv[1], "r");
1129 edges = edges_new (tv);
1130 while (getline (&line, &len, file) != -1) {
1134 "(%lf, %lf), (%lf, %lf) %lf %lf %d",
1135 &e.line.p1.x, &e.line.p1.y,
1136 &e.line.p2.x, &e.line.p2.y,
1139 edges = _edges_add_edge (tv, edges, &e);
1141 if (edges->num_edges) {
1142 g_print ("read %d edges\n", edges->num_edges);
1143 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1144 edges->extents.p1.x, edges->extents.p1.y,
1145 edges->extents.p2.x, edges->extents.p2.y);
1146 edges = edges_new (tv);
1151 if (edges->num_edges) {
1152 g_print ("read %d edges\n", edges->num_edges);
1153 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1154 edges->extents.p1.x, edges->extents.p1.y,
1155 edges->extents.p2.x, edges->extents.p2.y);
1161 file = fopen (argv[2], "r");
1163 traps = traps_new (tv);
1164 while (getline (&line, &len, file) != -1) {
1168 "%lf %lf L:(%lf, %lf), (%lf, %lf) R:(%lf, %lf), (%lf, %lf)",
1170 &t.left.p1.x, &t.left.p1.y,
1171 &t.left.p2.x, &t.left.p2.y,
1172 &t.right.p1.x, &t.right.p1.y,
1173 &t.right.p2.x, &t.right.p2.y) == 10) {
1174 traps = _traps_add_trapezoid (tv, traps, &t);
1176 if (traps->num_traps) {
1177 g_print ("read %d trapezoids\n", traps->num_traps);
1178 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1179 traps->extents.p1.x, traps->extents.p1.y,
1180 traps->extents.p2.x, traps->extents.p2.y);
1181 traps = traps_new (tv);
1186 if (traps->num_traps) {
1187 g_print ("read %d trapezoids\n", traps->num_traps);
1188 g_print ("extents=(%lg, %lg), (%lg, %lg)\n",
1189 traps->extents.p1.x, traps->extents.p1.y,
1190 traps->extents.p2.x, traps->extents.p2.y);
1198 tv2 = g_object_new (trap_view_get_type (), NULL);
1199 gtk_box_pack_start (GTK_BOX (hbox), &tv2->widget, TRUE, TRUE, 0);
1200 gtk_widget_show (&tv2->widget);
1202 tv2->traps_list = tv->traps_list;
1203 tv2->current_traps = tv->current_traps;
1205 tv2->group_prev = group_prev;
1206 tv2->group_next = NULL;
1207 group_prev->group_next = tv2;
1209 tv2->group_head = group_head;
1211 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1212 g_signal_connect (window, "delete-event",
1213 G_CALLBACK (gtk_main_quit), NULL);
1214 gtk_widget_set_size_request (window, 800, 800);
1215 gtk_container_add (GTK_CONTAINER (window), hbox);
1216 gtk_widget_show (hbox);
1217 gtk_widget_show (window);