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.20 by greg, Wed Mar 23 00:58:35 2022 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 <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         16              /* #components we support */
13 > #ifndef MAXCOMP
14 > #define MAXCOMP         MAXCSAMP        /* #components we support */
15 > #endif
16  
17 < /* unary matrix operation(s) */
17 > /* Unary matrix operation(s) */
18   typedef struct {
19        double          sca[MAXCOMP];           /* scalar coefficients */
19          double          cmat[MAXCOMP*MAXCOMP];  /* component transformation */
20 <        short           nsf;                    /* number of scalars */
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) */
27 > /* Matrix input source and requested operation(s) */
28   typedef struct {
29          const char      *inspec;                /* input specification */
30          RMPref          rmp;                    /* matrix preference */
# Line 35 | Line 36 | typedef struct {
36   int     verbose = 0;                    /* verbose reporting? */
37  
38   /* Load matrix */
39 < static int
39 > int
40   loadmatrix(ROPMAT *rop)
41   {
42          if (rop->mtx != NULL)           /* already loaded? */
43                  return(0);
44  
45          rop->mtx = rmx_load(rop->inspec, rop->rmp);
46 <        if (rop->mtx == NULL) {
47 <                fputs(rop->inspec, stderr);
48 <                fputs(": cannot load matrix\n", stderr);
46 >
47 >        return(!rop->mtx ? -1 : 1);
48 > }
49 >
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 >        static const char       *curRF = NULL;
57 >        static RMATRIX          refm;
58 >        const int               nc = rop->mtx->ncomp;
59 >        int                     i;
60 >
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 (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 <        return(1);
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 +                }
258 +        }
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 < static RMATRIX *
272 > RMATRIX *
273   loadop(ROPMAT *rop)
274   {
275 +        int     outtype = 0;
276          RMATRIX *mres;
277 <        int     i;
277 >        int     i, j;
278  
279          if (loadmatrix(rop) < 0)                /* make sure we're loaded */
280                  return(NULL);
281  
282 <        if (rop->preop.nsf > 0) {               /* apply scalar(s) */
283 <                if (rop->preop.clen > 0) {
284 <                        fputs("Options -s and -c are exclusive\n", stderr);
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 (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];
# Line 86 | Line 344 | loadop(ROPMAT *rop)
344                          fputs(" )\n", stderr);
345                  }
346          }
347 <        if (rop->preop.clen > 0) {      /* apply transform */
90 <                if (rop->preop.clen % rop->mtx->ncomp) {
91 <                        fprintf(stderr, "%s: -c must have N x %d coefficients\n",
92 <                                        rop->inspec, rop->mtx->ncomp);
93 <                        goto failure;
94 <                }
95 <                mres = rmx_transform(rop->mtx, rop->preop.clen/rop->mtx->ncomp,
96 <                                        rop->preop.cmat);
97 <                if (mres == NULL) {
98 <                        fprintf(stderr, "%s: matrix transform failed\n",
99 <                                                rop->inspec);
100 <                        goto failure;
101 <                }
102 <                if (verbose)
103 <                        fprintf(stderr, "%s: applied %d x %d transform\n",
104 <                                        rop->inspec, mres->ncomp,
105 <                                        rop->mtx->ncomp);
106 <                rmx_free(rop->mtx);
107 <                rop->mtx = mres;
108 <        }
109 <        if (rop->preop.transpose) {     /* transpose matrix? */
347 >        if (rop->preop.transpose) {             /* transpose matrix? */
348                  mres = rmx_transpose(rop->mtx);
349                  if (mres == NULL) {
350                          fputs(rop->inspec, stderr);
# Line 122 | Line 360 | loadop(ROPMAT *rop)
360          }
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);
# Line 129 | Line 369 | failure:
369   }
370  
371   /* Execute binary operation, free matrix arguments and return new result */
372 < static RMATRIX *
372 > RMATRIX *
373   binaryop(const char *inspec, RMATRIX *mleft, int op, RMATRIX *mright)
374   {
375          RMATRIX *mres = NULL;
# Line 206 | Line 446 | binaryop(const char *inspec, RMATRIX *mleft, int op, R
446   }
447  
448   /* Perform matrix operations from left to right */
449 < static RMATRIX *
449 > RMATRIX *
450   op_left2right(ROPMAT *mop)
451   {
452          RMATRIX *mleft = loadop(mop);
# Line 222 | Line 462 | op_left2right(ROPMAT *mop)
462   }
463  
464   /* Perform matrix operations from right to left */
465 < static RMATRIX *
465 > RMATRIX *
466   op_right2left(ROPMAT *mop)
467   {
468          RMATRIX *mright;
# Line 251 | Line 491 | op_right2left(ROPMAT *mop)
491                                                  : (mop)->mtx->ncols)
492  
493   /* Should we prefer concatenating from rightmost matrix towards left? */
494 < static int
494 > int
495   prefer_right2left(ROPMAT *mop)
496   {
497          int     mri = 0;
# Line 278 | Line 518 | prefer_right2left(ROPMAT *mop)
518          return(t_ncols(mop+mri) < t_nrows(mop));
519   }
520  
521 < static int
521 > int
522   get_factors(double da[], int n, char *av[])
523   {
524          int     ac;
# Line 288 | Line 528 | get_factors(double da[], int n, char *av[])
528          return(ac);
529   }
530  
531 < static ROPMAT *
532 < grow_moparray(ROPMAT *mop, int n2alloc)
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 grow_moparray()\n", stderr);
543 >                fputs("Out of memory in resize_moparr()\n", stderr);
544                  exit(1);
545          }
546          if (n2alloc > nmats)
# Line 309 | Line 552 | grow_moparray(ROPMAT *mop, int n2alloc)
552   int
553   main(int argc, char *argv[])
554   {
555 <        int     outfmt = DTfromHeader;
556 <        int     nall = 2;
557 <        ROPMAT  *mop = (ROPMAT *)calloc(nall, sizeof(ROPMAT));
558 <        int     nmats = 0;
559 <        RMATRIX *mres = NULL;
560 <        int     stdin_used = 0;
561 <        int     i;
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] &&
# Line 338 | Line 582 | main(int argc, char *argv[])
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++;
# Line 373 | Line 619 | main(int argc, char *argv[])
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                                  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')
# Line 395 | Line 663 | main(int argc, char *argv[])
663                          }
664                  }
665                  if (nmats >= nall)
666 <                        mop = grow_moparray(mop, nall += 2);
666 >                        mop = resize_moparr(mop, nall += 2);
667          }
668          if (mop[0].inspec == NULL)      /* nothing to do? */
669                  goto userr;
# Line 415 | Line 683 | main(int argc, char *argv[])
683          mres = loadop(mop+nmats);
684          if (mres == NULL)
685                  return(1);
686 <                                        /* write result to stdout */
419 <        if (outfmt == DTfromHeader)
686 >        if (outfmt == DTfromHeader)     /* check data type */
687                  outfmt = mres->dtype;
688 <        if (outfmt != DTascii)
689 <                SET_FILE_BINARY(stdout);
690 <        newheader("RADIANCE", stdout);
691 <        printargs(argc, argv, stdout);
692 <        if (!rmx_write(mres, outfmt, stdout)) {
426 <                fprintf(stderr, "%s: error writing result matrix\n", argv[0]);
427 <                return(1);
688 >        if (outfmt == DTrgbe) {
689 >                if (mres->ncomp > 3)
690 >                        outfmt = DTspec;
691 >                else if (mres->dtype == DTxyze)
692 >                        outfmt = DTxyze;
693          }
694 <        /* rmx_free(mres); free(mop); */
695 <        return(0);
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 ..][-rf|-rb] 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