Date:2010-09-24 21:42:36 (8 years 8 months ago)
Author:Werner Almesberger
Commit:898970b3dd4a792377cf26e25a546c97a064c8f4
Message:Instead of performing the tranformations stepwise for each point, pre-calculate them once.

- solidify/matrix.h, solidify/matrix.c: 2D matrix operations
- solidify/Makefile (OBJS): added matrix.o
- solidify/face.h (struct matrix): moved to solidify/matrix.h
- solidify/overlap.c (point, merge_matrix, draw_map): precalculate a single
vA+b transformation instead of stepwise transforming the vector inside
the loop
- solidify/overlap.c (do_shift): now that the math is right (or at least
better), reverse the shift
Files: solidify/Makefile (1 diff)
solidify/face.h (2 diffs)
solidify/matrix.c (1 diff)
solidify/matrix.h (1 diff)
solidify/overlap.c (3 diffs)

Change Details

solidify/Makefile
1212
1313SHELL = /bin/bash
1414
15OBJS = array.o face.o histo.o level.o overlap.o solid.o solidify.o style.o \
16       util.o
15OBJS = array.o face.o histo.o level.o matrix.o overlap.o solid.o solidify.o \
16       style.o util.o
1717
1818CFLAGS_WARN = -Wall -Wshadow -Wmissing-prototypes \
1919          -Wmissing-declarations -Wno-format-zero-length
solidify/face.h
1414#define FACE_H
1515
1616#include "array.h"
17#include "matrix.h"
1718
1819
19/*
20 * 2D transformation:
21 *
22 * x' = x*a[0][0]+y*a[0][1]+b[0]
23 * y' = x*a[1][0]+y*a[1][1]+b[1]
24 */
25
26
27struct matrix {
28    double a[2][2];
29    double b[2];
30};
31
3220struct face {
3321    struct array *a;
3422    int sx, sy; /* size */
...... 
4735
4836struct face *read_face(const char *name);
4937
50#endif /* FACE_H */
38#endif /* !FACE_H */
solidify/matrix.c
1/*
2 * matrix.c - 2D matrix operations
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 <assert.h>
15
16#include "matrix.h"
17
18
19void matrix_identity(struct matrix *m)
20{
21    m->a[0][0] = m->a[1][1] = 1;
22    m->a[0][1] = m->a[1][0] = 0;
23    m->b[0] = m->b[1] = 0;
24}
25
26
27void matrix_invert(const double m[2][2], double res[2][2])
28{
29    double det = m[0][0]*m[1][1]-m[0][1]*m[1][0];
30
31    assert(res != (void *) m);
32    res[0][0] = m[1][1]/det;
33    res[0][1] = -m[0][1]/det;
34    res[1][0] = -m[1][0]/det;
35    res[1][1] = m[0][0]/det;
36}
37
38
39void matrix_mult(double a[2][2], double b[2][2], double res[2][2])
40{
41    assert(res != a);
42    assert(res != b);
43    res[0][0] = a[0][0]*b[0][0]+a[0][1]*b[1][0];
44    res[0][1] = a[0][0]*b[0][1]+a[0][1]*b[1][1];
45    res[1][0] = a[1][0]*b[0][0]+a[1][1]*b[1][0];
46    res[1][1] = a[1][0]*b[0][1]+a[1][1]*b[1][1];
47}
48
49
50void matrix_multv(const double v[2], double m[2][2], double res[2])
51{
52    double tmp;
53
54    tmp = v[0]*m[0][0]+v[1]*m[0][1];
55    res[1] = v[0]*m[1][0]+v[1]*m[1][1];
56    res[0] = tmp;
57}
58
59
60void matrix_copy(double from[2][2], double to[2][2])
61{
62    to[0][0] = from[0][0];
63    to[0][1] = from[0][1];
64    to[1][0] = from[1][0];
65    to[1][1] = from[1][1];
66}
solidify/matrix.h
1/*
2 * matrix.h - 2D matrix operations
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#ifndef MATRIX_H
14#define MATRIX_H
15
16/*
17 * 2D transformation:
18 *
19 * x' = x*a[0][0]+y*a[0][1]+b[0]
20 * y' = x*a[1][0]+y*a[1][1]+b[1]
21 */
22
23
24struct matrix {
25    double a[2][2];
26    double b[2];
27};
28
29
30void matrix_identity(struct matrix *m);
31void matrix_invert(const double m[2][2], double res[2][2]);
32void matrix_mult(double a[2][2], double b[2][2], double res[2][2]);
33void matrix_multv(const double v[2], double m[2][2], double res[2]);
34void matrix_copy(double from[2][2], double to[2][2]);
35
36
37static inline void matrix_map(int x, int y, const struct matrix *m,
38    double *res_x, double *res_y)
39{
40    *res_x = x*m->a[0][0]+y*m->a[0][1]+m->b[0];
41    *res_y = x*m->a[1][0]+y*m->a[1][1]+m->b[1];
42
43}
44
45#endif /* !MATRIX_H */
solidify/overlap.c
9292 * - our model runs from min_x to max_x. Its center is at cx.
9393 */
9494
95static void point(const struct solid *s, int x, int y, guchar *p)
95static void point(const struct solid *s, int x, int y, guchar *p,
96    const struct matrix *ma, const struct matrix *mb)
9697{
9798    double za, zb, z;
98    int xa, xb, ya, yb;
9999    double xaf, xbf, yaf, ybf;
100100
101    xa = x-sx(s)/2;
102    ya = y-sy(s)/2;
103    xaf = xa*s->a->m.a[0][0]+ya*s->a->m.a[0][1]+s->a->m.b[0]+s->a->cx;
104    yaf = xa*s->a->m.a[1][0]+ya*s->a->m.a[1][1]+s->a->m.b[1]+s->a->cy;
105    za = zmix(s->a, xaf, yaf);
101    matrix_map(x, y, ma, &xaf, &yaf);
102    matrix_map(x, y, mb, &xbf, &ybf);
106103
107    xb = x-sx(s)/2;
108    yb = (sy(s)-1)/2-y;
109    xbf = xb*s->b->m.a[0][0]+yb*s->b->m.a[0][1]+s->b->m.b[0]+s->b->cx;
110    ybf = xb*s->b->m.a[1][0]+yb*s->b->m.a[1][1]+s->b->m.b[1]+s->b->cy;
104    za = zmix(s->a, xaf, yaf);
111105    zb = zmix(s->b, xbf, ybf);
112106
113107    if (za == UNDEF_F && zb == UNDEF_F)
...... 
158152}
159153
160154
155static void merge_matrix(struct matrix *m, const struct solid *s,
156    const struct face *f)
157{
158    double tm[2][2], tm2[2][2];
159    double tv[2];
160    double f_x, f_y;
161
162    /*
163     * Finally, we convert to model matrix coordinates.
164     *
165     * v' = v+c
166     */
167
168    m->b[0] += f->cx;
169    m->b[1] += f->cy;
170
171    /*
172     * Apply shrinkage caused by rotation out of z0. We use that
173     * cos a = sqrt(1-sin^2 a)
174     */
175
176    f_x = 1.0/sqrt(1-f->fx*f->fx);
177    f_y = 1.0/sqrt(1-f->fy*f->fy);
178
179    m->a[0][0] *= f_x;
180    m->a[0][1] *= f_x;
181    m->b[0] *= f_x;
182    m->a[1][0] *= f_y;
183    m->a[1][1] *= f_y;
184    m->b[1] *= f_y;
185
186    /*
187     * The transformation matrix f->m describes a transformation of
188     * (centered) model coordinates. We therefore have to reverse it:
189     *
190     * v = v'A+b
191     * v-b = v'A
192     * (v-b)A^-1 = v'
193     * vA^-1-bA^-1 = v'
194     */
195
196    matrix_invert(f->m.a, tm);
197    matrix_multv(f->m.b, tm, tv);
198    tv[0] = -tv[0];
199    tv[1] = -tv[1];
200
201    /*
202     * Merge with the transformations we have so far:
203     *
204     * v' = vA1+b1 the transformation we have so far
205     * v'' = v'A2+b2 the transformation we apply
206     *
207     * v'' = (vA1+b1)A2+b2
208     * v'' = vA1A2+b1A2+b2
209     */
210
211    /*
212     * So far, the theory. To make it really work, we have to calculate
213     * v'' = vA1A2+b1+b2
214     * duh ?!?
215     */
216
217    matrix_mult(m->a, tm, tm2); /* A1A2 */
218    matrix_copy(tm2, m->a);
219// matrix_multv(m->b, tm, m->b); /* b1A2 */
220    m->b[0] += tv[0]; /* b2 */
221    m->b[1] += tv[1];
222
223    /*
224     * Our input is a screen coordinate, its origin is in a corner so we
225     * first have to make it center-based:
226     *
227     * v' = (v-s/2)A+b
228     * v' = vA+(b-s/2*A)
229     */
230
231    tv[0] = sx(s)/2;
232    tv[1] = sy(s)/2;
233    matrix_multv(tv, m->a, tv);
234    m->b[0] -= tv[0];
235    m->b[1] -= tv[1];
236}
237
238
161239static void draw_map(GtkWidget *widget, struct solid *s)
162240{
163241    guchar *rgbbuf, *p;
164242    int x, y;
243    struct matrix ma = {
244        .a = { { 1, 0 }, { 0, 1 } },
245        .b = { 0, 0 },
246    };
247    struct matrix mb = {
248        .a = { { 1, 0 }, { 0, 1 } }, /* @@@ why not a[1][1] = -1 ? */
249        .b = { 0, 0 },
250    };
165251
166252    rgbbuf = p = calloc(sx(s)*sy(s), 3);
167253    if (!rgbbuf) {
168254        perror("calloc");
169255        exit(1);
170256    }
257
258    merge_matrix(&ma, s, s->a);
259    merge_matrix(&mb, s, s->b);
260
171261    for (y = sy(s)-1; y >= 0; y--)
172262        for (x = 0; x != sx(s) ; x++) {
173            point(s, x, y, p);
263            point(s, x, y, p, &ma, &mb);
174264            p += 3;
175265        }
176266    gdk_draw_rgb_image(widget->window,
...... 
221311
222312static void do_shift(struct matrix *m, int dx, int dy)
223313{
224    m->b[0] -= dx;
225    m->b[1] += dy;
314    m->b[0] += dx;
315    m->b[1] -= dy;
226316}
227317
228318

Archive Download the corresponding diff file

Branches:
master



interactive