Root/solidify/overlap.c

Source at commit 1fa23c574e532cd0a398661828a03912e6a2039c created 9 years 8 months ago.
By Werner Almesberger, Introduce a solid data type and use it, mainly in overlap()
1/*
2 * overlap.c - Overlap two parallel faces
3 *
4 * Written 2010 by Werner Almesberger
5 * Copyright 2010 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdlib.h>
15#include <stdio.h>
16#include <math.h>
17#include <limits.h>
18#include <gtk/gtk.h>
19
20#include "face.h"
21#include "solid.h"
22#include "overlap.h"
23
24
25#define UNDEF_F HUGE_VAL
26#define BORDER 10 /* pixels around the minimum drawing area */
27
28
29static int sx(const struct solid *s)
30{
31    return (s->a->sx > s->b->sx ? s->a->sx : s->b->sx)+2*BORDER;
32}
33
34
35static int sy(const struct solid *s)
36{
37    return (s->a->sy > s->b->sy ? s->a->sy : s->b->sy)+2*BORDER;
38}
39
40
41static double ramp(int z0, double w0, int z1, double w1)
42{
43    if (z0 != UNDEF && z1 != UNDEF)
44        return w0 == 0 && w1 == 0 ? z0 : z0*w0+z1*w1;
45    if (z0 == UNDEF && z0 == UNDEF)
46        return UNDEF_F;
47    if (z0 == UNDEF && w0 < w1)
48        return z1;
49    if (z1 == UNDEF && w0 > w1)
50        return z0;
51    return UNDEF_F;
52}
53
54
55static double zmix(struct face *f, double x, double y)
56{
57    int xa, xb, ya, yb;
58    double zx0, zx1;
59
60    xa = floor(x);
61    xb = ceil(x);
62    ya = floor(y);
63    yb = ceil(y);
64
65    zx0 = ramp(
66        get_bounded(f->a, xa, ya), yb-y,
67        get_bounded(f->a, xa, yb), y-ya);
68    zx1 = ramp(
69        get_bounded(f->a, xb, ya), yb-y,
70        get_bounded(f->a, xb, yb), y-ya);
71
72    return ramp(zx0, xb-x, zx1, x-xa);
73}
74
75
76static void draw_image(GtkWidget *widget, struct solid *s)
77{
78    guchar *rgbbuf, *p;
79    int x, y;
80    double z;
81    struct face *f = s->a;
82
83    rgbbuf = p = calloc(sx(s)*sy(s), 3);
84    if (!rgbbuf) {
85        perror("calloc");
86        exit(1);
87    }
88    for (y = sy(s)-1; y >= 0; y--)
89        for (x = 0; x != sx(s) ; x++) {
90            int xa = x+f->a->min_x;
91            int ya = y+f->a->min_y;
92
93            z = zmix(f,
94                xa*f->m.a[0][0]+ya*f->m.a[0][1]+f->m.b[0],
95                xa*f->m.a[1][0]+ya*f->m.a[1][1]+f->m.b[1]);
96            if (z == UNDEF_F) {
97                p += 3;
98                continue;
99            }
100            z = 256.0*(z-f->a->min_z)/(f->a->max_z-f->a->min_z);
101            if (z < 0)
102                z = 0;
103            if (z > 255)
104                z = 255;
105            *p++ = z;
106            *p++ = z;
107            *p++ = z;
108        }
109    gdk_draw_rgb_image(widget->window,
110        widget->style->fg_gc[GTK_STATE_NORMAL],
111        0, 0, sx(s), sy(s), GDK_RGB_DITHER_MAX, rgbbuf, sx(s)*3);
112    free(rgbbuf);
113}
114
115
116/*
117 * Rotate such that a point at distance "r" moves one unit. Rotate
118 * counter-clockwise for r > 1, clockwise for r < 0.
119 */
120
121static void rotate(struct matrix *m, double r)
122{
123    struct matrix t;
124    double s, c;
125
126    s = 1/r;
127    c = sqrt(1-s*s);
128    t.a[0][0] = m->a[0][0]*c-m->a[1][0]*s;
129    t.a[0][1] = m->a[0][1]*c-m->a[1][1]*s;
130    t.a[1][0] = m->a[1][0]*c+m->a[0][0]*s;
131    t.a[1][1] = m->a[1][1]*c+m->a[0][1]*s;
132    t.b[0] = m->b[0]*c-m->b[1]*s;
133    t.b[1] = m->b[0]*s+m->b[1]*c;
134    *m = t;
135}
136
137
138static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event,
139    gpointer data)
140{
141    GtkWidget *da = gtk_bin_get_child(GTK_BIN(widget));
142    struct solid *s = data;
143    struct face *f = s->a;
144    int dx = event->x-f->sx/2;
145    int dy = event->y-f->sy/2;
146    double r = hypot(dx, dy);
147
148    if (r < 1)
149        return TRUE;
150    switch (event->direction) {
151    case GDK_SCROLL_UP:
152        rotate(&f->m, r);
153        draw_image(da, s);
154        break;
155    case GDK_SCROLL_DOWN:
156        rotate(&f->m, -r);
157        draw_image(da, s);
158        break;
159    default:
160        /* ignore */;
161    }
162    return TRUE;
163}
164
165
166static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event,
167    gpointer user_data)
168{
169    draw_image(widget, user_data);
170    return TRUE;
171}
172
173
174
175void overlap(GtkWidget *canvas, struct solid *s)
176{
177    GtkWidget *evbox, *da;
178
179    evbox = gtk_event_box_new();
180    da = gtk_drawing_area_new();
181    gtk_widget_set_size_request(da, sx(s), sy(s));
182    gtk_container_add(GTK_CONTAINER(canvas), evbox);
183    gtk_container_add(GTK_CONTAINER(evbox), da);
184
185    draw_image(da, s);
186
187    g_signal_connect(G_OBJECT(evbox), "scroll-event",
188        G_CALLBACK(scroll_event), s);
189    g_signal_connect(G_OBJECT(da), "expose-event",
190        G_CALLBACK(expose_event), s);
191}
192

Archive Download this file

Branches:
master



interactive