Root/solidify/overlap.c

Source at commit 525e1557ec1a8e924b25a86c1efe61c93da21179 created 8 years 11 months ago.
By Werner Almesberger, Use two faces and show how they overlap (in progress)
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 point(const struct solid *s, int x, int y, guchar *p)
77{
78    double za, zb, z;
79    int xa = x+s->a->a->min_x;
80    int ya = y+s->a->a->min_y;
81    int yb = sy(s)-1-y+s->a->a->min_y;
82
83    za = zmix(s->a,
84        xa*s->a->m.a[0][0]+ya*s->a->m.a[0][1]+s->a->m.b[0],
85        xa*s->a->m.a[1][0]+ya*s->a->m.a[1][1]+s->a->m.b[1]);
86
87    zb = zmix(s->b,
88        xa*s->b->m.a[0][0]+yb*s->b->m.a[0][1]+s->b->m.b[0],
89        xa*s->b->m.a[1][0]+yb*s->b->m.a[1][1]+s->b->m.b[1]);
90
91    if (za == UNDEF_F && zb == UNDEF_F)
92        return;
93
94    if (za == UNDEF_F) {
95        z = 128.0*(zb-s->b->a->min_z)/(s->b->a->max_z-s->b->a->min_z);
96        if (z < 0)
97            z = 0;
98        if (z > 255)
99            z = 255;
100        p[0] = 255;
101        p[1] = z;
102        p[2] = z;
103        return;
104    }
105    if (zb == UNDEF_F) {
106        z = 128.0*(za-s->a->a->min_z)/(s->a->a->max_z-s->a->a->min_z);
107        if (z < 0)
108            z = 0;
109        if (z > 255)
110            z = 255;
111        p[0] = z;
112        p[1] = 255;
113        p[2] = z;
114        return;
115    }
116
117    z = za;
118    za -= face_z0(s->a, xa, ya);
119    zb -= face_z0(s->b, xa, yb);
120
121    if (za+zb < -s->dist) {
122        p[0] = 0;
123        p[1] = 0;
124        p[2] = 255;
125        return;
126    }
127
128    z = 256.0*(z-s->a->a->min_z)/(s->a->a->max_z-s->a->a->min_z);
129    if (z < 0)
130        z = 0;
131    if (z > 255)
132        z = 255;
133    p[0] = z;
134    p[1] = z;
135    p[2] = z;
136}
137
138
139static void draw_image(GtkWidget *widget, struct solid *s)
140{
141    guchar *rgbbuf, *p;
142    int x, y;
143
144    rgbbuf = p = calloc(sx(s)*sy(s), 3);
145    if (!rgbbuf) {
146        perror("calloc");
147        exit(1);
148    }
149    for (y = sy(s)-1; y >= 0; y--)
150        for (x = 0; x != sx(s) ; x++) {
151            point(s, x, y, p);
152            p += 3;
153        }
154    gdk_draw_rgb_image(widget->window,
155        widget->style->fg_gc[GTK_STATE_NORMAL],
156        0, 0, sx(s), sy(s), GDK_RGB_DITHER_MAX, rgbbuf, sx(s)*3);
157    free(rgbbuf);
158}
159
160
161/*
162 * Rotate such that a point at distance "r" moves one unit. Rotate
163 * counter-clockwise for r > 1, clockwise for r < 0.
164 */
165
166static void rotate(struct matrix *m, double r)
167{
168    struct matrix t;
169    double s, c;
170
171    s = 1/r;
172    c = sqrt(1-s*s);
173    t.a[0][0] = m->a[0][0]*c-m->a[1][0]*s;
174    t.a[0][1] = m->a[0][1]*c-m->a[1][1]*s;
175    t.a[1][0] = m->a[1][0]*c+m->a[0][0]*s;
176    t.a[1][1] = m->a[1][1]*c+m->a[0][1]*s;
177    t.b[0] = m->b[0]*c-m->b[1]*s;
178    t.b[1] = m->b[0]*s+m->b[1]*c;
179    *m = t;
180}
181
182
183static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event,
184    gpointer data)
185{
186    GtkWidget *da = gtk_bin_get_child(GTK_BIN(widget));
187    struct solid *s = data;
188    struct face *f = s->a;
189    int dx = event->x-f->sx/2;
190    int dy = event->y-f->sy/2;
191    double r = hypot(dx, dy);
192
193    if (r < 1)
194        return TRUE;
195    switch (event->direction) {
196    case GDK_SCROLL_UP:
197        rotate(&f->m, r);
198        draw_image(da, s);
199        break;
200    case GDK_SCROLL_DOWN:
201        rotate(&f->m, -r);
202        draw_image(da, s);
203        break;
204    default:
205        /* ignore */;
206    }
207    return TRUE;
208}
209
210
211static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event,
212    gpointer user_data)
213{
214    draw_image(widget, user_data);
215    return TRUE;
216}
217
218
219
220void overlap(GtkWidget *canvas, struct solid *s)
221{
222    GtkWidget *evbox, *da;
223
224    evbox = gtk_event_box_new();
225    da = gtk_drawing_area_new();
226    gtk_widget_set_size_request(da, sx(s), sy(s));
227    gtk_container_add(GTK_CONTAINER(canvas), evbox);
228    gtk_container_add(GTK_CONTAINER(evbox), da);
229
230    draw_image(da, s);
231
232    g_signal_connect(G_OBJECT(evbox), "scroll-event",
233        G_CALLBACK(scroll_event), s);
234    g_signal_connect(G_OBJECT(da), "expose-event",
235        G_CALLBACK(expose_event), s);
236}
237

Archive Download this file

Branches:
master



interactive