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

Comparing ray/src/util/cmatrix.c (file contents):
Revision 2.4 by greg, Thu May 29 17:28:09 2014 UTC vs.
Revision 2.21 by greg, Mon Aug 12 18:28:37 2019 UTC

# Line 8 | Line 8 | static const char RCSid[] = "$Id$";
8   */
9  
10   #include <ctype.h>
11 + #include "platform.h"
12   #include "standard.h"
13   #include "cmatrix.h"
14   #include "platform.h"
15 + #include "paths.h"
16   #include "resolu.h"
17  
18   const char      *cm_fmt_id[] = {
19 <                        "unknown", "ascii", "float", "double",
20 <                        COLRFMT, CIEFMT
19 >                        "unknown", "ascii", COLRFMT, CIEFMT,
20 >                        "float", "double"
21                  };
22  
23   const int       cm_elem_size[] = {
24 <                        0, 0, 3*sizeof(float), 3*sizeof(double), 4, 4
24 >                        0, 0, 4, 4, 3*sizeof(float), 3*sizeof(double)
25                  };
26  
27   /* Allocate a color coefficient matrix */
# Line 32 | Line 34 | cm_alloc(int nrows, int ncols)
34                  error(USER, "attempt to create empty matrix");
35          cm = (CMATRIX *)malloc(sizeof(CMATRIX) +
36                                  sizeof(COLOR)*(nrows*ncols - 1));
37 <        if (cm == NULL)
37 >        if (!cm)
38                  error(SYSTEM, "out of memory in cm_alloc()");
39          cm->nrows = nrows;
40          cm->ncols = ncols;
41          return(cm);
42   }
43  
44 + static void
45 + adjacent_ra_sizes(size_t bounds[2], size_t target)
46 + {
47 +        bounds[0] = 0; bounds[1] = 2048;
48 +        while (bounds[1] < target) {
49 +                bounds[0] = bounds[1];
50 +                bounds[1] += bounds[1]>>1;
51 +        }
52 + }
53 +
54   /* Resize color coefficient matrix */
55   CMATRIX *
56   cm_resize(CMATRIX *cm, int nrows)
57   {
58 +        size_t  old_size, new_size, ra_bounds[2];
59 +
60 +        if (!cm)
61 +                return(NULL);
62          if (nrows == cm->nrows)
63                  return(cm);
64          if (nrows <= 0) {
65                  cm_free(cm);
66                  return(NULL);
67          }
68 <        cm = (CMATRIX *)realloc(cm, sizeof(CMATRIX) +
69 <                        sizeof(COLOR)*(nrows*cm->ncols - 1));
70 <        if (cm == NULL)
71 <                error(SYSTEM, "out of memory in cm_resize()");
68 >        old_size = sizeof(CMATRIX) + sizeof(COLOR)*(cm->nrows*cm->ncols - 1);
69 >        adjacent_ra_sizes(ra_bounds, old_size);
70 >        new_size = sizeof(CMATRIX) + sizeof(COLOR)*(nrows*cm->ncols - 1);
71 >        if (nrows < cm->nrows ? new_size <= ra_bounds[0] :
72 >                                new_size > ra_bounds[1]) {
73 >                adjacent_ra_sizes(ra_bounds, new_size);
74 >                cm = (CMATRIX *)realloc(cm, ra_bounds[1]);
75 >                if (!cm)
76 >                        error(SYSTEM, "out of memory in cm_resize()");
77 >        }
78          cm->nrows = nrows;
79          return(cm);
80   }
81  
82 + typedef struct {
83 +        int     dtype;          /* data type */
84 +        int     nrows, ncols;   /* matrix size */
85 +        char    *err;           /* error message */
86 + } CMINFO;               /* header info record */
87 +
88   static int
89 < getDT(char *s, void *p)
89 > get_cminfo(char *s, void *p)
90   {
91 <        char    fmt[32];
91 >        CMINFO  *ip = (CMINFO *)p;
92 >        char    fmt[MAXFMTLEN];
93          int     i;
94 <        
94 >
95 >        if (!strncmp(s, "NCOMP=", 6) && atoi(s+6) != 3) {
96 >                ip->err = "unexpected # components (must be 3)";
97 >                return(-1);
98 >        }
99 >        if (!strncmp(s, "NROWS=", 6)) {
100 >                ip->nrows = atoi(s+6);
101 >                return(0);
102 >        }
103 >        if (!strncmp(s, "NCOLS=", 6)) {
104 >                ip->ncols = atoi(s+6);
105 >                return(0);
106 >        }
107          if (!formatval(fmt, s))
108                  return(0);
109          for (i = 1; i < DTend; i++)
110                  if (!strcmp(fmt, cm_fmt_id[i]))
111 <                        *((int *)p) = i;
111 >                        ip->dtype = i;
112          return(0);
113   }
114  
115 < /* Load header to obtain data type */
116 < int
117 < getDTfromHeader(FILE *fp)
115 > /* Load header to obtain/check data type and number of columns */
116 > char *
117 > cm_getheader(int *dt, int *nr, int *nc, FILE *fp)
118   {
119 <        int     dt = DTfromHeader;
120 <        
121 <        if (getheader(fp, getDT, &dt) < 0)
122 <                error(SYSTEM, "header read error");
123 <        if (dt == DTfromHeader)
124 <                error(USER, "missing data format in header");
125 <        return(dt);
119 >        CMINFO  cmi;
120 >                                                /* read header */
121 >        cmi.dtype = DTfromHeader;
122 >        cmi.nrows = cmi.ncols = 0;
123 >        cmi.err = "unexpected EOF in header";
124 >        if (getheader(fp, get_cminfo, &cmi) < 0)
125 >                return(cmi.err);
126 >        if (dt) {                               /* get/check data type? */
127 >                if (cmi.dtype == DTfromHeader) {
128 >                        if (*dt == DTfromHeader)
129 >                                return("missing/unknown data format in header");
130 >                } else if (*dt == DTfromHeader)
131 >                        *dt = cmi.dtype;
132 >                else if (*dt != cmi.dtype)
133 >                        return("unexpected data format in header");
134 >        }
135 >        if (nr) {                               /* get/check #rows? */
136 >                if (*nr <= 0)
137 >                        *nr = cmi.nrows;
138 >                else if ((cmi.nrows > 0) & (*nr != cmi.nrows))
139 >                        return("unexpected row count in header");
140 >        }
141 >        if (nc) {                               /* get/check #columns? */
142 >                if (*nc <= 0)
143 >                        *nc = cmi.ncols;
144 >                else if ((cmi.ncols > 0) & (*nc != cmi.ncols))
145 >                        return("unexpected column count in header");
146 >        }
147 >        return(NULL);
148   }
149  
150 < /* Allocate and load a matrix from the given file (or stdin if NULL) */
150 > /* Allocate and load a matrix from the given input (or stdin if NULL) */
151   CMATRIX *
152 < cm_load(const char *fname, int nrows, int ncols, int dtype)
152 > cm_load(const char *inspec, int nrows, int ncols, int dtype)
153   {
154 <        FILE    *fp = stdin;
155 <        CMATRIX *cm;
154 >        const int       ROWINC = 2048;
155 >        FILE            *fp = stdin;
156 >        CMATRIX         *cm;
157  
158 <        if (ncols <= 0)
159 <                error(USER, "Non-positive number of columns");
160 <        if (fname == NULL)
161 <                fname = "<stdin>";
162 <        else if ((fp = fopen(fname, "r")) == NULL) {
163 <                sprintf(errmsg, "cannot open file '%s'", fname);
158 >        if (!inspec)
159 >                inspec = "<stdin>";
160 >        else if (inspec[0] == '!') {
161 >                fp = popen(inspec+1, "r");
162 >                if (!fp) {
163 >                        sprintf(errmsg, "cannot start command '%s'", inspec);
164 >                        error(SYSTEM, errmsg);
165 >                }
166 >        } else if (!(fp = fopen(inspec, "r"))) {
167 >                sprintf(errmsg, "cannot open file '%s'", inspec);
168                  error(SYSTEM, errmsg);
169          }
170   #ifdef getc_unlocked
# Line 104 | Line 172 | cm_load(const char *fname, int nrows, int ncols, int d
172   #endif
173          if (dtype != DTascii)
174                  SET_FILE_BINARY(fp);            /* doesn't really work */
175 <        if (dtype == DTfromHeader)
176 <                dtype = getDTfromHeader(fp);
175 >        if (!dtype | !ncols) {                  /* expecting header? */
176 >                char    *err = cm_getheader(&dtype, &nrows, &ncols, fp);
177 >                if (err)
178 >                        error(USER, err);
179 >                if (ncols <= 0)
180 >                        error(USER, "unspecified number of columns");
181 >        }
182          switch (dtype) {
183          case DTascii:
184          case DTfloat:
# Line 116 | Line 189 | cm_load(const char *fname, int nrows, int ncols, int d
189          }
190          if (nrows <= 0) {                       /* don't know length? */
191                  int     guessrows = 147;        /* usually big enough */
192 <                if ((dtype != DTascii) & (fp != stdin)) {
192 >                if ((dtype != DTascii) & (fp != stdin) & (inspec[0] != '!')) {
193                          long    startpos = ftell(fp);
194                          if (fseek(fp, 0L, SEEK_END) == 0) {
195                                  long    endpos = ftell(fp);
# Line 126 | Line 199 | cm_load(const char *fname, int nrows, int ncols, int d
199                                  if ((endpos - startpos) % (ncols*elemsiz)) {
200                                          sprintf(errmsg,
201                                          "improper length for binary file '%s'",
202 <                                                        fname);
202 >                                                        inspec);
203                                          error(USER, errmsg);
204                                  }
205                                  guessrows = (endpos - startpos)/(ncols*elemsiz);
206                                  if (fseek(fp, startpos, SEEK_SET) < 0) {
207                                          sprintf(errmsg,
208                                                  "fseek() error on file '%s'",
209 <                                                        fname);
209 >                                                        inspec);
210                                          error(SYSTEM, errmsg);
211                                  }
212                                  nrows = guessrows;      /* we're confident */
# Line 142 | Line 215 | cm_load(const char *fname, int nrows, int ncols, int d
215                  cm = cm_alloc(guessrows, ncols);
216          } else
217                  cm = cm_alloc(nrows, ncols);
218 <        if (cm == NULL)                                 /* XXX never happens */
218 >        if (!cm)                                        /* XXX never happens */
219                  return(NULL);
220          if (dtype == DTascii) {                         /* read text file */
221                  int     maxrow = (nrows > 0 ? nrows : 32000);
222                  int     r, c;
223                  for (r = 0; r < maxrow; r++) {
224                      if (r >= cm->nrows)                 /* need more space? */
225 <                        cm = cm_resize(cm, 2*cm->nrows);
225 >                        cm = cm_resize(cm, cm->nrows+ROWINC);
226                      for (c = 0; c < ncols; c++) {
227                          COLORV  *cv = cm_lval(cm,r,c);
228 <                        if (fscanf(fp, COLSPEC, cv, cv+1, cv+2) != 3)
228 >                        if (fscanf(fp, COLSPEC, cv, cv+1, cv+2) != 3) {
229                                  if ((nrows <= 0) & (r > 0) & !c) {
230                                          cm = cm_resize(cm, maxrow=r);
231                                          break;
232                                  } else
233                                          goto EOFerror;
234 +                        }
235                      }
236                  }
237                  while ((c = getc(fp)) != EOF)
238                          if (!isspace(c)) {
239                                  sprintf(errmsg,
240 <                                "unexpected data at end of ascii file %s",
241 <                                                fname);
240 >                                "unexpected data at end of ascii input '%s'",
241 >                                                inspec);
242                                  error(WARNING, errmsg);
243                                  break;
244                          }
# Line 172 | Line 246 | cm_load(const char *fname, int nrows, int ncols, int d
246                  if (sizeof(COLOR) == cm_elem_size[dtype]) {
247                          int     nread = 0;
248                          do {                            /* read all we can */
249 <                                nread += fread(cm->cmem + 3*nread,
249 >                                nread += getbinary(cm->cmem + 3*nread,
250                                                  sizeof(COLOR),
251                                                  cm->nrows*cm->ncols - nread,
252                                                  fp);
253                                  if (nrows <= 0) {       /* unknown length */
254                                          if (nread == cm->nrows*cm->ncols)
255                                                          /* need more space? */
256 <                                                cm = cm_resize(cm, 2*cm->nrows);
256 >                                                cm = cm_resize(cm, cm->nrows+ROWINC);
257                                          else if (nread && !(nread % cm->ncols))
258                                                          /* seem to be  done */
259                                                  cm = cm_resize(cm, nread/cm->ncols);
# Line 197 | Line 271 | cm_load(const char *fname, int nrows, int ncols, int d
271                          if (n <= 0)
272                                  goto not_handled;
273                          while (n--) {
274 <                                if (fread(dc, sizeof(double), 3, fp) != 3)
274 >                                if (getbinary(dc, sizeof(double), 3, fp) != 3)
275                                          goto EOFerror;
276                                  copycolor(cvp, dc);
277                                  cvp += 3;
# Line 210 | Line 284 | cm_load(const char *fname, int nrows, int ncols, int d
284                          if (n <= 0)
285                                  goto not_handled;
286                          while (n--) {
287 <                                if (fread(fc, sizeof(float), 3, fp) != 3)
287 >                                if (getbinary(fc, sizeof(float), 3, fp) != 3)
288                                          goto EOFerror;
289                                  copycolor(cvp, fc);
290                                  cvp += 3;
# Line 218 | Line 292 | cm_load(const char *fname, int nrows, int ncols, int d
292                  }
293                  if (fgetc(fp) != EOF) {
294                                  sprintf(errmsg,
295 <                                "unexpected data at end of binary file %s",
296 <                                                fname);
295 >                                "unexpected data at end of binary input '%s'",
296 >                                                inspec);
297                                  error(WARNING, errmsg);
298                  }
299          }
300 <        if (fp != stdin)
301 <                fclose(fp);
300 >        if (fp != stdin) {
301 >                if (inspec[0] != '!')
302 >                        fclose(fp);
303 >                else if (pclose(fp)) {
304 >                        sprintf(errmsg, "error running command '%s'", inspec);
305 >                        error(WARNING, errmsg);
306 >                }
307 >        }
308   #ifdef getc_unlocked
309          else
310                  funlockfile(fp);
311   #endif
312          return(cm);
313   EOFerror:
314 <        sprintf(errmsg, "unexpected EOF reading %s", fname);
314 >        sprintf(errmsg, "unexpected EOF reading %s", inspec);
315          error(USER, errmsg);
316   not_handled:
317          error(INTERNAL, "unhandled data size or length in cm_load()");
# Line 245 | Line 325 | cm_column(const CMATRIX *cm, int c)
325          CMATRIX *cvr;
326          int     dr;
327  
328 +        if (!cm)
329 +                return(NULL);
330          if ((c < 0) | (c >= cm->ncols))
331                  error(INTERNAL, "column requested outside matrix");
332          cvr = cm_alloc(cm->nrows, 1);
333 <        if (cvr == NULL)
333 >        if (!cvr)
334                  return(NULL);
335          for (dr = 0; dr < cm->nrows; dr++) {
336                  const COLORV    *sp = cm_lval(cm,dr,c);
# Line 260 | Line 342 | cm_column(const CMATRIX *cm, int c)
342          return(cvr);
343   }
344  
263 /* Scale a matrix by a single value */
264 CMATRIX *
265 cm_scale(const CMATRIX *cm1, const COLOR sca)
266 {
267        CMATRIX *cmr;
268        int     dr, dc;
269
270        cmr = cm_alloc(cm1->nrows, cm1->ncols);
271        if (cmr == NULL)
272                return(NULL);
273        for (dr = 0; dr < cmr->nrows; dr++)
274            for (dc = 0; dc < cmr->ncols; dc++) {
275                const COLORV    *sp = cm_lval(cm1,dr,dc);
276                COLORV          *dp = cm_lval(cmr,dr,dc);
277                dp[0] = sp[0] * sca[0];
278                dp[1] = sp[1] * sca[1];
279                dp[2] = sp[2] * sca[2];
280            }
281        return(cmr);
282 }
283
345   /* Multiply two matrices (or a matrix and a vector) and allocate the result */
346   CMATRIX *
347   cm_multiply(const CMATRIX *cm1, const CMATRIX *cm2)
# Line 289 | Line 350 | cm_multiply(const CMATRIX *cm1, const CMATRIX *cm2)
350          CMATRIX *cmr;
351          int     dr, dc, i;
352  
353 +        if (!cm1 | !cm2)
354 +                return(NULL);
355          if ((cm1->ncols <= 0) | (cm1->ncols != cm2->nrows))
356                  error(INTERNAL, "matrix dimension mismatch in cm_multiply()");
357          cmr = cm_alloc(cm1->nrows, cm2->ncols);
358 <        if (cmr == NULL)
358 >        if (!cmr)
359                  return(NULL);
360                                  /* optimization: check for zero rows & cols */
361          if (((cm1->nrows > 5) | (cm2->ncols > 5)) & (cm1->ncols > 5)) {
# Line 317 | Line 380 | cm_multiply(const CMATRIX *cm1, const CMATRIX *cm2)
380                  COLORV  *dp = cm_lval(cmr,dr,dc);
381                  double  res[3];
382                  dp[0] = dp[1] = dp[2] = 0;
383 <                if (rowcheck != NULL && !rowcheck[dr])
383 >                if (rowcheck && !rowcheck[dr])
384                          continue;
385 <                if (colcheck != NULL && !colcheck[dc])
385 >                if (colcheck && !colcheck[dc])
386                          continue;
387                  res[0] = res[1] = res[2] = 0;
388                  for (i = 0; i < cm1->ncols; i++) {
389                      const COLORV        *cp1 = cm_lval(cm1,dr,i);
390                      const COLORV        *cp2 = cm_lval(cm2,i,dc);
391 <                    res[0] += cp1[0] * cp2[0];
392 <                    res[1] += cp1[1] * cp2[1];
393 <                    res[2] += cp1[2] * cp2[2];
391 >                    res[0] += (double)cp1[0] * cp2[0];
392 >                    res[1] += (double)cp1[1] * cp2[1];
393 >                    res[2] += (double)cp1[2] * cp2[2];
394                  }
395                  copycolor(dp, res);
396              }
397 <        if (rowcheck != NULL) free(rowcheck);
398 <        if (colcheck != NULL) free(colcheck);
397 >        if (rowcheck) free(rowcheck);
398 >        if (colcheck) free(colcheck);
399          return(cmr);
400   }
401  
# Line 341 | Line 404 | int
404   cm_write(const CMATRIX *cm, int dtype, FILE *fp)
405   {
406          static const char       tabEOL[2] = {'\t','\n'};
407 <        const COLORV            *mp = cm->cmem;
407 >        const COLORV            *mp;
408          int                     r, c;
409  
410 +        if (!cm)
411 +                return(0);
412 +        mp = cm->cmem;
413          switch (dtype) {
414          case DTascii:
415                  for (r = 0; r < cm->nrows; r++)
# Line 357 | Line 423 | cm_write(const CMATRIX *cm, int dtype, FILE *fp)
423                  if (sizeof(COLOR) == cm_elem_size[dtype]) {
424                          r = cm->ncols*cm->nrows;
425                          while (r > 0) {
426 <                                c = fwrite(mp, sizeof(COLOR), r, fp);
426 >                                c = putbinary(mp, sizeof(COLOR), r, fp);
427                                  if (c <= 0)
428                                          return(0);
429                                  mp += 3*c;
# Line 368 | Line 434 | cm_write(const CMATRIX *cm, int dtype, FILE *fp)
434                          r = cm->ncols*cm->nrows;
435                          while (r--) {
436                                  copycolor(dc, mp);
437 <                                if (fwrite(dc, sizeof(double), 3, fp) != 3)
437 >                                if (putbinary(dc, sizeof(double), 3, fp) != 3)
438                                          return(0);
439                                  mp += 3;
440                          }
# Line 377 | Line 443 | cm_write(const CMATRIX *cm, int dtype, FILE *fp)
443                          r = cm->ncols*cm->nrows;
444                          while (r--) {
445                                  copycolor(fc, mp);
446 <                                if (fwrite(fc, sizeof(float), 3, fp) != 3)
446 >                                if (putbinary(fc, sizeof(float), 3, fp) != 3)
447                                          return(0);
448                                  mp += 3;
449                          }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines