ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rmtxop.c
(Generate patch)

Comparing ray/src/util/rmtxop.c (file contents):
Revision 2.9 by schorsch, Sun Mar 6 01:13:18 2016 UTC vs.
Revision 2.36 by greg, Fri Mar 28 00:06:36 2025 UTC

# Line 5 | Line 5 | static const char RCSid[] = "$Id$";
5   * General component matrix operations.
6   */
7  
8 < #include <stdio.h>
9 < #include <stdlib.h>
8 > #include <errno.h>
9   #include "rtio.h"
11 #include "resolu.h"
10   #include "rmatrix.h"
11 + #include "platform.h"
12  
13 < #define MAXCOMP         50              /* #components we support */
13 > #ifndef MAXCOMP
14 > #define MAXCOMP         MAXCSAMP        /* #components we support */
15 > #endif
16  
17 + /* Unary matrix operation(s) */
18   typedef struct {
17        double          sca[MAXCOMP];           /* scalar coefficients */
18        int             nsf;                    /* number of scalars */
19          double          cmat[MAXCOMP*MAXCOMP];  /* component transformation */
20 <        int             clen;                   /* number of coefficients */
21 <        int             transpose;              /* do transpose? */
22 <        int             op;                     /* '*' or '+' */
23 < } ROPERAT;                              /* matrix operation */
20 >        double          sca[MAXCOMP];           /* scalar coefficients */
21 >        const char      *csym;                  /* symbolic coefs or file */
22 >        short           clen;                   /* number of coefficients */
23 >        short           nsf;                    /* number of scalars */
24 >        short           transpose;              /* do transpose? */
25 > } RUNARYOP;
26  
27 + /* Matrix input source and requested operation(s) */
28 + typedef struct {
29 +        const char      *inspec;                /* input specification */
30 +        RMPref          rmp;                    /* matrix preference */
31 +        RUNARYOP        preop;                  /* unary operation(s) */
32 +        RMATRIX         *mtx;                   /* original matrix if loaded */
33 +        int             binop;                  /* binary op with next (or 0) */
34 + } ROPMAT;
35 +
36   int     verbose = 0;                    /* verbose reporting? */
37  
38 < static void
39 < op_default(ROPERAT *op)
38 > /* Load matrix */
39 > int
40 > loadmatrix(ROPMAT *rop)
41   {
42 <        memset(op, 0, sizeof(ROPERAT));
43 <        op->op = '*';
42 >        if (rop->mtx != NULL)           /* already loaded? */
43 >                return(0);
44 >
45 >        rop->mtx = rmx_load(rop->inspec, rop->rmp);
46 >
47 >        return(!rop->mtx ? -1 : 1);
48   }
49  
50 < static RMATRIX *
51 < operate(RMATRIX *mleft, ROPERAT *op, const char *fname)
50 > extern int      checksymbolic(ROPMAT *rop);
51 >
52 > /* Check/set transform based on a reference input file */
53 > int
54 > checkreffile(ROPMAT *rop)
55   {
56 <        RMATRIX *mright = rmx_load(fname);
57 <        RMATRIX *mtmp;
58 <        int     i;
56 >        static const char       *curRF = NULL;
57 >        static RMATRIX          refm;
58 >        const int               nc = rop->mtx->ncomp;
59 >        int                     i;
60  
61 <        if (fname == NULL)
62 <                fname = "<stdin>";
63 <        if (mright == NULL) {
64 <                fputs(fname, stderr);
65 <                fputs(": cannot load matrix\n", stderr);
66 <                return(NULL);
61 >        if (!curRF || strcmp(rop->preop.csym, curRF)) {
62 >                FILE    *fp = fopen(rop->preop.csym, "rb");
63 >                if (!rmx_load_header(&refm, fp)) {
64 >                        fprintf(stderr, "%s: cannot read info header\n",
65 >                                        rop->preop.csym);
66 >                        curRF = NULL;
67 >                        if (fp) fclose(fp);
68 >                        return(-1);
69 >                }
70 >                fclose(fp);
71 >                curRF = rop->preop.csym;
72          }
73 <        if (op->transpose) {            /* transpose matrix? */
74 <                mtmp = rmx_transpose(mright);
75 <                if (mtmp == NULL) {
76 <                        fputs(fname, stderr);
77 <                        fputs(": transpose failed\n", stderr);
78 <                        rmx_free(mright);
79 <                        return(NULL);
73 >        if (refm.ncomp == 3) {
74 >                rop->preop.csym = (refm.dtype == DTxyze) ? "XYZ" : "RGB";
75 >                return(checksymbolic(rop));
76 >        }
77 >        if (refm.ncomp == 2) {
78 >                fprintf(stderr, "%s: cannot convert to 2 components\n",
79 >                                curRF);
80 >                return(-1);
81 >        }
82 >        if (refm.ncomp == 1) {
83 >                rop->preop.csym = "Y";          /* XXX big assumption */
84 >                return(checksymbolic(rop));
85 >        }
86 >        if (refm.ncomp == nc &&
87 >                        !memcmp(refm.wlpart, rop->mtx->wlpart, sizeof(refm.wlpart)))
88 >                return(0);                      /* nothing to do */
89 >
90 >        if ((nc <= 3) | (nc > MAXCSAMP) | (refm.ncomp > MAXCSAMP)) {
91 >                fprintf(stderr, "%s: cannot resample from %d to %d components\n",
92 >                                curRF, nc, refm.ncomp);
93 >                return(-1);
94 >        }
95 >        rop->preop.clen = refm.ncomp * nc;      /* compute spec to ref */
96 >
97 >        for (i = 0; i < nc; i++) {
98 >                SCOLOR  scstim, scresp;
99 >                int     j;
100 >                memset(scstim, 0, sizeof(COLORV)*nc);
101 >                scstim[i] = 1.f;
102 >                convertscolor(scresp, refm.ncomp, refm.wlpart[0], refm.wlpart[3],
103 >                                scstim, nc, rop->mtx->wlpart[0], rop->mtx->wlpart[3]);
104 >                for (j = refm.ncomp; j-- > 0; )
105 >                        rop->preop.cmat[j*nc + i] = scresp[j];
106 >        }
107 >        memcpy(rop->mtx->wlpart, refm.wlpart, sizeof(rop->mtx->wlpart));
108 >        return(0);
109 > }
110 >
111 > /* Compute conversion row from spectrum to one channel of RGB */
112 > void
113 > rgbrow(ROPMAT *rop, int r, int p)
114 > {
115 >        const int       nc = rop->mtx->ncomp;
116 >        const float *   wlp = rop->mtx->wlpart;
117 >        int             i;
118 >
119 >        for (i = nc; i--; ) {
120 >                int     nmEnd = wlp[0] + (wlp[3] - wlp[0])*i/nc;
121 >                int     nmStart = wlp[0] + (wlp[3] - wlp[0])*(i+1)/nc;
122 >                COLOR   crgb;
123 >                spec_rgb(crgb, nmStart, nmEnd);
124 >                rop->preop.cmat[r*nc+i] = crgb[p];
125 >        }
126 > }
127 >
128 > /* Compute conversion row from spectrum to one channel of XYZ */
129 > void
130 > xyzrow(ROPMAT *rop, int r, int p)
131 > {
132 >        const int       nc = rop->mtx->ncomp;
133 >        const float *   wlp = rop->mtx->wlpart;
134 >        int             i;
135 >
136 >        for (i = nc; i--; ) {
137 >                int     nmEnd = wlp[0] + (wlp[3] - wlp[0])*i/nc;
138 >                int     nmStart = wlp[0] + (wlp[3] - wlp[0])*(i+1)/nc;
139 >                COLOR   cxyz;
140 >                spec_cie(cxyz, nmStart, nmEnd);
141 >                rop->preop.cmat[r*nc+i] = cxyz[p];
142 >        }
143 > }
144 >
145 > /* Use the spectral sensitivity function to compute matrix coefficients */
146 > void
147 > sensrow(ROPMAT *rop, int r, double (*sf)(const SCOLOR sc, int ncs, const float wlpt[4]))
148 > {
149 >        const int       nc = rop->mtx->ncomp;
150 >        int             i;
151 >
152 >        for (i = nc; i--; ) {
153 >                SCOLOR  sclr;
154 >                memset(sclr, 0, sizeof(COLORV)*nc);
155 >                sclr[i] = 1.f;
156 >                rop->preop.cmat[r*nc+i] = (*sf)(sclr, nc, rop->mtx->wlpart);
157 >        }
158 > }
159 >
160 > /* Check/set symbolic transform */
161 > int
162 > checksymbolic(ROPMAT *rop)
163 > {
164 >        const int       nc = rop->mtx->ncomp;
165 >        const int       dt = rop->mtx->dtype;
166 >        double          cf = 1;
167 >        int             i, j;
168 >                                        /* check suffix => reference file */
169 >        if (strchr(rop->preop.csym, '.') > rop->preop.csym)
170 >                return(checkreffile(rop));
171 >
172 >        if (nc < 3) {
173 >                fprintf(stderr, "%s: -c '%s' requires at least 3 components\n",
174 >                                rop->inspec, rop->preop.csym);
175 >                return(-1);
176 >        }
177 >        rop->preop.clen = strlen(rop->preop.csym) * nc;
178 >        if (rop->preop.clen > MAXCOMP*MAXCOMP) {
179 >                fprintf(stderr, "%s: -c '%s' results in too many components\n",
180 >                                rop->inspec, rop->preop.csym);
181 >                return(-1);
182 >        }
183 >        for (j = 0; rop->preop.csym[j]; j++) {
184 >                int     comp = 0;
185 >                switch (rop->preop.csym[j]) {
186 >                case 'B':
187 >                case 'b':
188 >                        ++comp;
189 >                        /* fall through */
190 >                case 'G':
191 >                case 'g':
192 >                        ++comp;
193 >                        /* fall through */
194 >                case 'R':
195 >                case 'r':
196 >                        if (rop->preop.csym[j] <= 'Z')
197 >                                cf = 1./WHTEFFICACY;
198 >                        if (dt == DTxyze) {
199 >                                for (i = 3; i--; )
200 >                                        rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
201 >                        } else if (nc == 3)
202 >                                rop->preop.cmat[j*nc+comp] = 1.;
203 >                        else
204 >                                rgbrow(rop, j, comp);
205 >                        break;
206 >                case 'Z':
207 >                case 'z':
208 >                        ++comp;
209 >                        /* fall through */
210 >                case 'Y':
211 >                case 'y':
212 >                        ++comp;
213 >                        /* fall through */
214 >                case 'X':
215 >                case 'x':
216 >                        if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
217 >                                cf = WHTEFFICACY;
218 >                        if (dt == DTxyze) {
219 >                                rop->preop.cmat[j*nc+comp] = 1.;
220 >                        } else if (nc == 3) {
221 >                                for (i = 3; i--; )
222 >                                        rop->preop.cmat[j*nc+i] =
223 >                                                        rgb2xyzmat[comp][i];
224 >                        } else if (comp == CIEY)
225 >                                sensrow(rop, j, scolor2photopic);
226 >                        else
227 >                                xyzrow(rop, j, comp);
228 >
229 >                        for (i = nc*(cf != 1); i--; )
230 >                                rop->preop.cmat[j*nc+i] *= cf;
231 >                        break;
232 >                case 'S':               /* scotopic (il)luminance */
233 >                        cf = WHTSCOTOPIC;
234 >                        /* fall through */
235 >                case 's':
236 >                        sensrow(rop, j, scolor2scotopic);
237 >                        for (i = nc*(cf != 1); i--; )
238 >                                rop->preop.cmat[j*nc+i] *= cf;
239 >                        break;
240 >                case 'M':               /* melanopic (il)luminance */
241 >                        cf = WHTMELANOPIC;
242 >                        /* fall through */
243 >                case 'm':
244 >                        sensrow(rop, j, scolor2melanopic);
245 >                        for (i = nc*(cf != 1); i--; )
246 >                                rop->preop.cmat[j*nc+i] *= cf;
247 >                        break;
248 >                case 'A':               /* average component */
249 >                case 'a':
250 >                        for (i = nc; i--; )
251 >                                rop->preop.cmat[j*nc+i] = 1./(double)nc;
252 >                        break;
253 >                default:
254 >                        fprintf(stderr, "%s: -c '%c' unsupported\n",
255 >                                rop->inspec, rop->preop.csym[j]);
256 >                        return(-1);
257                  }
56                if (verbose) {
57                        fputs(fname, stderr);
58                        fputs(": transposed rows and columns\n", stderr);
59                }
60                rmx_free(mright);
61                mright = mtmp;
258          }
259 <        if (op->nsf > 0) {              /* apply scalar(s) */
260 <                if (op->clen > 0) {
261 <                        fputs("Options -s and -c are exclusive\n", stderr);
262 <                        rmx_free(mright);
263 <                        return(NULL);
259 >                                        /* return recommended output type */
260 >        if (!strcasecmp(rop->preop.csym, "XYZ")) {
261 >                if (dt <= DTspec)
262 >                        return(DTxyze);
263 >        } else if (!strcasecmp(rop->preop.csym, "RGB")) {
264 >                if (dt <= DTspec)
265 >                        return(DTrgbe);
266 >        } else if (dt == DTspec)
267 >                return(DTfloat);        /* probably not actual spectrum */
268 >        return(0);
269 > }
270 >
271 > /* Get matrix and perform unary operations */
272 > RMATRIX *
273 > loadop(ROPMAT *rop)
274 > {
275 >        int     outtype = 0;
276 >        RMATRIX *mres;
277 >        int     i, j;
278 >
279 >        if (loadmatrix(rop) < 0)                /* make sure we're loaded */
280 >                return(NULL);
281 >
282 >        if (rop->preop.csym &&                  /* symbolic transform? */
283 >                        (outtype = checksymbolic(rop)) < 0)
284 >                goto failure;
285 >        if (rop->preop.clen > 0) {              /* apply component transform? */
286 >                if (rop->preop.clen % rop->mtx->ncomp) {
287 >                        fprintf(stderr, "%s: -c must have N x %d coefficients\n",
288 >                                        rop->inspec, rop->mtx->ncomp);
289 >                        goto failure;
290                  }
291 <                if (op->nsf == 1) {
292 <                        for (i = mright->ncomp; --i; )
293 <                                op->sca[i] = op->sca[0];
294 <                } else if (op->nsf != mright->ncomp) {
291 >                if (rop->preop.nsf > 0) {       /* scale transform, first */
292 >                        if (rop->preop.nsf == 1) {
293 >                                for (i = rop->preop.clen; i--; )
294 >                                        rop->preop.cmat[i] *= rop->preop.sca[0];
295 >                        } else if (rop->preop.nsf*rop->mtx->ncomp != rop->preop.clen) {
296 >                                fprintf(stderr, "%s: -s must have one or %d factors\n",
297 >                                                rop->inspec,
298 >                                                rop->preop.clen/rop->mtx->ncomp);
299 >                                goto failure;
300 >                        } else {
301 >                                for (i = rop->preop.nsf; i--; )
302 >                                        for (j = rop->mtx->ncomp; j--; )
303 >                                                rop->preop.cmat[i*rop->mtx->ncomp+j]
304 >                                                                *= rop->preop.sca[i];
305 >                        }
306 >                }
307 >                mres = rmx_transform(rop->mtx, rop->preop.clen/rop->mtx->ncomp,
308 >                                        rop->preop.cmat);
309 >                if (mres == NULL) {
310 >                        fprintf(stderr, "%s: matrix transform failed\n",
311 >                                                rop->inspec);
312 >                        goto failure;
313 >                }
314 >                if (verbose)
315 >                        fprintf(stderr, "%s: applied %d x %d transform%s\n",
316 >                                        rop->inspec, mres->ncomp,
317 >                                        rop->mtx->ncomp,
318 >                                        rop->preop.nsf ? " (* scalar)" : "");
319 >                rop->preop.nsf = 0;             /* now folded in */
320 >                if ((mres->ncomp > 3) & (mres->dtype <= DTspec))
321 >                        outtype = DTfloat;      /* probably not actual spectrum */
322 >                rmx_free(rop->mtx);
323 >                rop->mtx = mres;
324 >        }
325 >        if (rop->preop.nsf > 0) {               /* apply scalar(s)? */
326 >                if (rop->preop.nsf == 1) {
327 >                        for (i = rop->mtx->ncomp; --i; )
328 >                                rop->preop.sca[i] = rop->preop.sca[0];
329 >                } else if (rop->preop.nsf != rop->mtx->ncomp) {
330                          fprintf(stderr, "%s: -s must have one or %d factors\n",
331 <                                        fname, mright->ncomp);
332 <                        rmx_free(mright);
76 <                        return(NULL);
331 >                                        rop->inspec, rop->mtx->ncomp);
332 >                        goto failure;
333                  }
334 <                if ((mleft == NULL) | (op->op != '+') &&
335 <                                !rmx_scale(mright, op->sca)) {
80 <                        fputs(fname, stderr);
334 >                if (!rmx_scale(rop->mtx, rop->preop.sca)) {
335 >                        fputs(rop->inspec, stderr);
336                          fputs(": scalar operation failed\n", stderr);
337 <                        rmx_free(mright);
83 <                        return(NULL);
337 >                        goto failure;
338                  }
339                  if (verbose) {
340 <                        fputs(fname, stderr);
340 >                        fputs(rop->inspec, stderr);
341                          fputs(": applied scalar (", stderr);
342 <                        for (i = 0; i < op->nsf; i++)
343 <                                fprintf(stderr, " %f", op->sca[i]);
342 >                        for (i = 0; i < rop->preop.nsf; i++)
343 >                                fprintf(stderr, " %f", rop->preop.sca[i]);
344                          fputs(" )\n", stderr);
345                  }
346          }
347 <        if (op->clen > 0) {             /* apply transform */
348 <                if (op->clen % mright->ncomp) {
349 <                        fprintf(stderr, "%s: -c must have N x %d coefficients\n",
350 <                                        fname, mright->ncomp);
351 <                        rmx_free(mright);
352 <                        return(NULL);
347 >        if (rop->preop.transpose) {             /* transpose matrix? */
348 >                mres = rmx_transpose(rop->mtx);
349 >                if (mres == NULL) {
350 >                        fputs(rop->inspec, stderr);
351 >                        fputs(": transpose failed\n", stderr);
352 >                        goto failure;
353                  }
354 <                mtmp = rmx_transform(mright, op->clen/mright->ncomp, op->cmat);
355 <                if (mtmp == NULL) {
356 <                        fprintf(stderr, "%s: matrix transform failed\n", fname);
103 <                        rmx_free(mright);
104 <                        return(NULL);
354 >                if (verbose) {
355 >                        fputs(rop->inspec, stderr);
356 >                        fputs(": transposed rows and columns\n", stderr);
357                  }
358 <                if (verbose)
359 <                        fprintf(stderr, "%s: applied %d x %d transform\n",
108 <                                        fname, mtmp->ncomp, mright->ncomp);
109 <                rmx_free(mright);
110 <                mright = mtmp;
358 >                rmx_free(rop->mtx);
359 >                rop->mtx = mres;
360          }
361 <        if (mleft == NULL)              /* just one matrix */
362 <                return(mright);
363 <        if (op->op == '*') {            /* concatenate */
364 <                RMATRIX *mres = rmx_multiply(mleft, mright);
361 >        mres = rop->mtx;
362 >        rop->mtx = NULL;
363 >        if (outtype)
364 >                mres->dtype = outtype;
365 >        return(mres);
366 > failure:
367 >        rmx_free(rop->mtx);
368 >        return(rop->mtx = NULL);
369 > }
370 >
371 > /* Execute binary operation, free matrix arguments and return new result */
372 > RMATRIX *
373 > binaryop(const char *inspec, RMATRIX *mleft, int op, RMATRIX *mright)
374 > {
375 >        RMATRIX *mres = NULL;
376 >        int     i;
377 >
378 >        if ((mleft == NULL) | (mright == NULL))
379 >                return(NULL);
380 >        switch (op) {
381 >        case '.':                       /* concatenate */
382 >                if (mleft->ncomp != mright->ncomp) {
383 >                        fputs(inspec, stderr);
384 >                        fputs(": # components do not match\n", stderr);
385 >                } else if (mleft->ncols != mright->nrows) {
386 >                        fputs(inspec, stderr);
387 >                        fputs(": mismatched dimensions\n",
388 >                                        stderr);
389 >                } else
390 >                        mres = rmx_multiply(mleft, mright);
391 >                rmx_free(mleft);
392 >                rmx_free(mright);
393                  if (mres == NULL) {
394 <                        fputs(fname, stderr);
395 <                        if (mleft->ncols != mright->nrows)
119 <                                fputs(": mismatched dimensions for multiply\n",
120 <                                                stderr);
121 <                        else
122 <                                fputs(": concatenation failed\n", stderr);
123 <                        rmx_free(mright);
394 >                        fputs(inspec, stderr);
395 >                        fputs(": concatenation failed\n", stderr);
396                          return(NULL);
397                  }
398                  if (verbose) {
399 <                        fputs(fname, stderr);
399 >                        fputs(inspec, stderr);
400                          fputs(": concatenated matrix\n", stderr);
401                  }
402 <                rmx_free(mright);
403 <                rmx_free(mleft);
404 <                mleft = mres;
405 <        } else if (op->op == '+') {
134 <                if (!rmx_sum(mleft, mright, op->nsf ? op->sca : (double *)NULL)) {
135 <                        fputs(fname, stderr);
402 >                break;
403 >        case '+':
404 >                if (!rmx_sum(mleft, mright, NULL)) {
405 >                        fputs(inspec, stderr);
406                          fputs(": matrix sum failed\n", stderr);
407 +                        rmx_free(mleft);
408                          rmx_free(mright);
409                          return(NULL);
410                  }
411                  if (verbose) {
412 <                        fputs(fname, stderr);
412 >                        fputs(inspec, stderr);
413                          fputs(": added in matrix\n", stderr);
414                  }
415                  rmx_free(mright);
416 <        } else {
417 <                fprintf(stderr, "%s: unknown operation '%c'\n", fname, op->op);
416 >                mres = mleft;
417 >                break;
418 >        case '*':
419 >        case '/': {
420 >                const char *    tnam = (op == '/') ?
421 >                                        "division" : "multiplication";
422 >                errno = 0;
423 >                if (!rmx_elemult(mleft, mright, (op == '/'))) {
424 >                        fprintf(stderr, "%s: element-wise %s failed\n",
425 >                                        inspec, tnam);
426 >                        rmx_free(mleft);
427 >                        rmx_free(mright);
428 >                        return(NULL);
429 >                }
430 >                if (errno)
431 >                        fprintf(stderr,
432 >                                "%s: warning - error during element-wise %s\n",
433 >                                        inspec, tnam);
434 >                else if (verbose)
435 >                        fprintf(stderr, "%s: element-wise %s\n", inspec, tnam);
436                  rmx_free(mright);
437 +                mres = mleft;
438 +                } break;
439 +        default:
440 +                fprintf(stderr, "%s: unknown operation '%c'\n", inspec, op);
441 +                rmx_free(mleft);
442 +                rmx_free(mright);
443                  return(NULL);
444          }
445 +        return(mres);
446 + }
447 +
448 + /* Perform matrix operations from left to right */
449 + RMATRIX *
450 + op_left2right(ROPMAT *mop)
451 + {
452 +        RMATRIX *mleft = loadop(mop);
453 +
454 +        while (mop->binop) {
455 +                if (mleft == NULL)
456 +                        break;
457 +                mleft = binaryop(mop[1].inspec,
458 +                                mleft, mop->binop, loadop(mop+1));
459 +                mop++;
460 +        }
461          return(mleft);
462   }
463  
464 < static int
464 > /* Perform matrix operations from right to left */
465 > RMATRIX *
466 > op_right2left(ROPMAT *mop)
467 > {
468 >        RMATRIX *mright;
469 >        int     rpos = 0;
470 >                                        /* find end of list */
471 >        while (mop[rpos].binop)
472 >                if (mop[rpos++].binop != '.') {
473 >                        fputs(
474 >                "Right-to-left evaluation only for matrix multiplication!\n",
475 >                                        stderr);
476 >                        return(NULL);
477 >                }
478 >        mright = loadop(mop+rpos);
479 >        while (rpos-- > 0) {
480 >                if (mright == NULL)
481 >                        break;
482 >                mright = binaryop(mop[rpos+1].inspec,
483 >                                loadop(mop+rpos), mop[rpos].binop, mright);
484 >        }
485 >        return(mright);
486 > }
487 >
488 > #define t_nrows(mop)    ((mop)->preop.transpose ? (mop)->mtx->ncols \
489 >                                                : (mop)->mtx->nrows)
490 > #define t_ncols(mop)    ((mop)->preop.transpose ? (mop)->mtx->nrows \
491 >                                                : (mop)->mtx->ncols)
492 >
493 > /* Should we prefer concatenating from rightmost matrix towards left? */
494 > int
495 > prefer_right2left(ROPMAT *mop)
496 > {
497 >        int     mri = 0;
498 >
499 >        while (mop[mri].binop)          /* find rightmost matrix */
500 >                if (mop[mri++].binop != '.')
501 >                        return(0);      /* pre-empt reversal for other ops */
502 >
503 >        if (mri <= 1)
504 >                return(0);              /* won't matter */
505 >
506 >        if (loadmatrix(mop+mri) < 0)    /* load rightmost cat */
507 >                return(1);              /* fail will bail in a moment */
508 >
509 >        if (t_ncols(mop+mri) == 1)
510 >                return(1);              /* definitely better R->L */
511 >
512 >        if (t_ncols(mop+mri) >= t_nrows(mop+mri))
513 >                return(0);              /* ...probably worse */
514 >
515 >        if (loadmatrix(mop) < 0)        /* load leftmost */
516 >                return(0);              /* fail will bail in a moment */
517 >
518 >        return(t_ncols(mop+mri) < t_nrows(mop));
519 > }
520 >
521 > int
522   get_factors(double da[], int n, char *av[])
523   {
524          int     ac;
# Line 160 | Line 528 | get_factors(double da[], int n, char *av[])
528          return(ac);
529   }
530  
531 + ROPMAT *
532 + resize_moparr(ROPMAT *mop, int n2alloc)
533 + {
534 +        int     nmats = 0;
535 +        int     i;
536 +
537 +        while (mop[nmats++].binop)
538 +                ;
539 +        for (i = nmats; i >= n2alloc; i--)
540 +                rmx_free(mop[i].mtx);
541 +        mop = (ROPMAT *)realloc(mop, n2alloc*sizeof(ROPMAT));
542 +        if (mop == NULL) {
543 +                fputs("Out of memory in resize_moparr()\n", stderr);
544 +                exit(1);
545 +        }
546 +        if (n2alloc > nmats)
547 +                memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
548 +        return(mop);
549 + }
550 +
551   /* Load one or more matrices and operate on them, sending results to stdout */
552   int
553   main(int argc, char *argv[])
554   {
555 <        int     outfmt = DTfromHeader;
556 <        RMATRIX *mres = NULL;
557 <        ROPERAT op;
558 <        int     i;
559 <                                        /* initialize */
560 <        op_default(&op);
555 >        int             outfmt = DTfromHeader;
556 >        const char      *defCsym = NULL;
557 >        int             nall = 2;
558 >        ROPMAT          *mop = (ROPMAT *)calloc(nall, sizeof(ROPMAT));
559 >        int             nmats = 0;
560 >        RMATRIX         *mres = NULL;
561 >        int             stdin_used = 0;
562 >        int             i;
563                                          /* get options and arguments */
564 <        for (i = 1; i < argc; i++)
565 <                if (argv[i][0] == '+' && !argv[i][1]) {
566 <                        op.op = '+';
567 <                } else if (argv[i][0] != '-' || !argv[i][1]) {
568 <                        char    *fname = NULL;  /* load matrix */
569 <                        if (argv[i][0] != '-')
570 <                                fname = argv[i];
571 <                        mres = operate(mres, &op, fname);
182 <                        if (mres == NULL) {
183 <                                fprintf(stderr, "%s: operation failed on '%s'\n",
184 <                                                argv[0], argv[i]);
185 <                                return(0);
564 >        for (i = 1; i < argc; i++) {
565 >                if (argv[i][0] && !argv[i][1] &&
566 >                                strchr(".+*/", argv[i][0]) != NULL) {
567 >                        if (!nmats || mop[nmats-1].binop) {
568 >                                fprintf(stderr,
569 >                        "%s: missing matrix argument before '%c' operation\n",
570 >                                                argv[0], argv[i][0]);
571 >                                return(1);
572                          }
573 <                        op_default(&op);        /* reset operator */
573 >                        mop[nmats-1].binop = argv[i][0];
574 >                } else if (argv[i][0] != '-' || !argv[i][1]) {
575 >                        if (argv[i][0] == '-') {
576 >                                if (stdin_used++) {
577 >                                        fprintf(stderr,
578 >                        "%s: standard input used for more than one matrix\n",
579 >                                                argv[0]);
580 >                                        return(1);
581 >                                }
582 >                                mop[nmats].inspec = stdin_name;
583 >                        } else
584 >                                mop[nmats].inspec = argv[i];
585 >                        if (!mop[nmats].preop.csym)
586 >                                mop[nmats].preop.csym = defCsym;
587 >                        if (nmats > 0 && !mop[nmats-1].binop)
588 >                                mop[nmats-1].binop = '.';
589 >                        nmats++;
590                  } else {
591                          int     n = argc-1 - i;
592                          switch (argv[i][1]) {   /* get option */
593                          case 'v':
594 <                                verbose = !verbose;
594 >                                verbose++;
595                                  break;
596                          case 'f':
597                                  switch (argv[i][2]) {
# Line 210 | Line 612 | main(int argc, char *argv[])
612                                  }
613                                  break;
614                          case 't':
615 <                                op.transpose = 1;
615 >                                mop[nmats].preop.transpose = 1;
616                                  break;
617                          case 's':
618                                  if (n > MAXCOMP) n = MAXCOMP;
619 <                                op.nsf = get_factors(op.sca, n, argv+i+1);
620 <                                i += op.nsf;
619 >                                i += mop[nmats].preop.nsf =
620 >                                        get_factors(mop[nmats].preop.sca,
621 >                                                        n, argv+i+1);
622 >                                if (mop[nmats].preop.nsf <= 0) {
623 >                                        fprintf(stderr, "%s: -s missing arguments\n",
624 >                                                        argv[0]);
625 >                                        goto userr;
626 >                                }
627                                  break;
628 +                        case 'C':
629 +                                if (!n || isflt(argv[i+1]))
630 +                                        goto userr;
631 +                                defCsym = mop[nmats].preop.csym = argv[++i];
632 +                                mop[nmats].preop.clen = 0;
633 +                                break;
634                          case 'c':
635 +                                if (n && !isflt(argv[i+1])) {
636 +                                        mop[nmats].preop.csym = argv[++i];
637 +                                        mop[nmats].preop.clen = 0;
638 +                                        break;
639 +                                }
640                                  if (n > MAXCOMP*MAXCOMP) n = MAXCOMP*MAXCOMP;
641 <                                op.clen = get_factors(op.cmat, n, argv+i+1);
642 <                                i += op.clen;
641 >                                i += mop[nmats].preop.clen =
642 >                                        get_factors(mop[nmats].preop.cmat,
643 >                                                        n, argv+i+1);
644 >                                if (mop[nmats].preop.clen <= 0) {
645 >                                        fprintf(stderr, "%s: -c missing arguments\n",
646 >                                                        argv[0]);
647 >                                        goto userr;
648 >                                }
649 >                                mop[nmats].preop.csym = NULL;
650                                  break;
651 +                        case 'r':
652 +                                if (argv[i][2] == 'f')
653 +                                        mop[nmats].rmp = RMPreflF;
654 +                                else if (argv[i][2] == 'b')
655 +                                        mop[nmats].rmp = RMPreflB;
656 +                                else
657 +                                        goto userr;
658 +                                break;
659                          default:
660                                  fprintf(stderr, "%s: unknown operation '%s'\n",
661                                                  argv[0], argv[i]);
662                                  goto userr;
663                          }
664                  }
665 <        if (mres == NULL)               /* check that we got something */
665 >                if (nmats >= nall)
666 >                        mop = resize_moparr(mop, nall += 2);
667 >        }
668 >        if (mop[0].inspec == NULL)      /* nothing to do? */
669                  goto userr;
670 <                                        /* write result to stdout */
671 <        if (outfmt == DTfromHeader)
672 <                outfmt = mres->dtype;
673 < #if defined(_WIN32) || defined(_WIN64)
237 <        if (outfmt != DTascii)
238 <                _setmode(fileno(stdout), _O_BINARY);
239 < #endif
240 <        newheader("RADIANCE", stdout);
241 <        printargs(argc, argv, stdout);
242 <        if (!rmx_write(mres, outfmt, stdout)) {
243 <                fprintf(stderr, "%s: error writing result matrix\n", argv[0]);
670 >        if (mop[nmats-1].binop) {
671 >                fprintf(stderr,
672 >                        "%s: missing matrix argument after '%c' operation\n",
673 >                                argv[0], mop[nmats-1].binop);
674                  return(1);
675          }
676 <        /* rmx_free(mres); mres = NULL; */
677 <        return(0);
676 >                                        /* favor quicker concatenation */
677 >        mop[nmats].mtx = prefer_right2left(mop) ? op_right2left(mop)
678 >                                                : op_left2right(mop);
679 >        if (mop[nmats].mtx == NULL)
680 >                return(1);
681 >                                        /* apply trailing unary operations */
682 >        mop[nmats].inspec = "trailing_ops";
683 >        mres = loadop(mop+nmats);
684 >        if (mres == NULL)
685 >                return(1);
686 >        if (outfmt == DTfromHeader)     /* check data type */
687 >                outfmt = mres->dtype;
688 >        if (outfmt == DTrgbe) {
689 >                if (mres->ncomp > 3)
690 >                        outfmt = DTspec;
691 >                else if (mres->dtype == DTxyze)
692 >                        outfmt = DTxyze;
693 >        }
694 >        newheader("RADIANCE", stdout);  /* write result to stdout */
695 >        printargs(argc, argv, stdout);
696 >        return(rmx_write(mres, outfmt, stdout) ? 0 : 1);
697   userr:
698          fprintf(stderr,
699 <        "Usage: %s [-v][-f[adfc][-t][-s sf .. | -c ce ..] m1 [+] .. > mres\n",
699 >        "Usage: %s [-v][-f{adfc}][-t][-s sf .. | -c ce ..][-rf|-rb] m1 [.+*/] .. > mres\n",
700                          argv[0]);
701          return(1);
702   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines