ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rmatrix.c
Revision: 2.14
Committed: Mon May 4 23:27:04 2015 UTC (8 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.13: +4 -2 lines
Log Message:
Minor type-checking fix

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rmatrix.c,v 2.13 2015/05/04 20:53:21 greg Exp $";
3 #endif
4 /*
5 * General matrix operations.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include "resolu.h"
13 #include "rmatrix.h"
14
15 static char rmx_mismatch_warn[] = "WARNING: data type mismatch\n";
16
17 /* Allocate a nr x nc matrix with n components */
18 RMATRIX *
19 rmx_alloc(int nr, int nc, int n)
20 {
21 RMATRIX *dnew;
22
23 if ((nr <= 0) | (nc <= 0) | (n <= 0))
24 return(NULL);
25 dnew = (RMATRIX *)malloc(sizeof(RMATRIX)-sizeof(dnew->mtx) +
26 sizeof(dnew->mtx[0])*(n*nr*nc));
27 if (dnew == NULL)
28 return(NULL);
29 dnew->nrows = nr; dnew->ncols = nc; dnew->ncomp = n;
30 dnew->dtype = DTdouble;
31 dnew->info = NULL;
32 return(dnew);
33 }
34
35 /* Free a RMATRIX array */
36 void
37 rmx_free(RMATRIX *rm)
38 {
39 if (!rm) return;
40 if (rm->info)
41 free(rm->info);
42 free(rm);
43 }
44
45 /* Resolve data type based on two input types (returns 0 for mismatch) */
46 int
47 rmx_newtype(int dtyp1, int dtyp2)
48 {
49 if ((dtyp1==DTxyze) | (dtyp1==DTrgbe) |
50 (dtyp2==DTxyze) | (dtyp2==DTrgbe)
51 && dtyp1 != dtyp2)
52 return(0);
53 if (dtyp1 < dtyp2)
54 return(dtyp1);
55 return(dtyp2);
56 }
57
58 /* Append header information associated with matrix data */
59 int
60 rmx_addinfo(RMATRIX *rm, const char *info)
61 {
62 if (!info || !*info)
63 return(0);
64 if (!rm->info) {
65 rm->info = (char *)malloc(strlen(info)+1);
66 if (rm->info) rm->info[0] = '\0';
67 } else
68 rm->info = (char *)realloc(rm->info,
69 strlen(rm->info)+strlen(info)+1);
70 if (!rm->info)
71 return(0);
72 strcat(rm->info, info);
73 return(1);
74 }
75
76 static int
77 get_dminfo(char *s, void *p)
78 {
79 RMATRIX *ip = (RMATRIX *)p;
80 char fmt[64];
81 int i;
82
83 if (headidval(fmt, s))
84 return(0);
85 if (!strncmp(s, "NCOMP=", 6)) {
86 ip->ncomp = atoi(s+6);
87 return(0);
88 }
89 if (!strncmp(s, "NROWS=", 6)) {
90 ip->nrows = atoi(s+6);
91 return(0);
92 }
93 if (!strncmp(s, "NCOLS=", 6)) {
94 ip->ncols = atoi(s+6);
95 return(0);
96 }
97 if (!formatval(fmt, s)) {
98 rmx_addinfo(ip, s);
99 return(0);
100 }
101 for (i = 1; i < DTend; i++)
102 if (!strcmp(fmt, cm_fmt_id[i])) {
103 ip->dtype = i;
104 return(0);
105 }
106 return(-1);
107 }
108
109 static int
110 rmx_load_ascii(RMATRIX *rm, FILE *fp)
111 {
112 int i, j, k;
113 #ifdef _WIN32
114 _setmode(fileno(fp), _O_TEXT);
115 #endif
116 for (i = 0; i < rm->nrows; i++)
117 for (j = 0; j < rm->ncols; j++)
118 for (k = 0; k < rm->ncomp; k++)
119 if (fscanf(fp, "%lf", &rmx_lval(rm,i,j,k)) != 1)
120 return(0);
121 return(1);
122 }
123
124 static int
125 rmx_load_float(RMATRIX *rm, FILE *fp)
126 {
127 int i, j, k;
128 float val[100];
129
130 if (rm->ncomp > 100) {
131 fputs("Unsupported # components in rmx_load_float()\n", stderr);
132 exit(1);
133 }
134 for (i = 0; i < rm->nrows; i++)
135 for (j = 0; j < rm->ncols; j++) {
136 if (fread(val, sizeof(val[0]), rm->ncomp, fp) != rm->ncomp)
137 return(0);
138 for (k = rm->ncomp; k--; )
139 rmx_lval(rm,i,j,k) = val[k];
140 }
141 return(1);
142 }
143
144 static int
145 rmx_load_double(RMATRIX *rm, FILE *fp)
146 {
147 int i, j, k;
148 double val[100];
149
150 if (rm->ncomp > 100) {
151 fputs("Unsupported # components in rmx_load_double()\n", stderr);
152 exit(1);
153 }
154 for (i = 0; i < rm->nrows; i++)
155 for (j = 0; j < rm->ncols; j++) {
156 if (fread(val, sizeof(val[0]), rm->ncomp, fp) != rm->ncomp)
157 return(0);
158 for (k = rm->ncomp; k--; )
159 rmx_lval(rm,i,j,k) = val[k];
160 }
161 return(1);
162 }
163
164 static int
165 rmx_load_rgbe(RMATRIX *rm, FILE *fp)
166 {
167 COLOR *scan = (COLOR *)malloc(sizeof(COLOR)*rm->ncols);
168 int i, j;
169
170 if (scan == NULL)
171 return(0);
172 for (i = 0; i < rm->nrows; i++) {
173 if (freadscan(scan, rm->ncols, fp) < 0) {
174 free(scan);
175 return(0);
176 }
177 for (j = rm->ncols; j--; ) {
178 rmx_lval(rm,i,j,0) = colval(scan[j],RED);
179 rmx_lval(rm,i,j,1) = colval(scan[j],GRN);
180 rmx_lval(rm,i,j,2) = colval(scan[j],BLU);
181 }
182 }
183 free(scan);
184 return(1);
185 }
186
187 /* Load matrix from supported file type */
188 RMATRIX *
189 rmx_load(const char *inspec)
190 {
191 FILE *fp = stdin;
192 RMATRIX dinfo;
193 RMATRIX *dnew;
194
195 if (inspec == NULL) { /* reading from stdin? */
196 inspec = "<stdin>";
197 #ifdef _WIN32
198 _setmode(fileno(stdin), _O_BINARY);
199 #endif
200 } else if (inspec[0] == '!') {
201 if ((fp = popen(inspec+1, "r")) == NULL)
202 return(NULL);
203 #ifdef _WIN32
204 _setmode(fileno(fp), _O_BINARY);
205 #endif
206 } else {
207 const char *sp = inspec; /* check suffix */
208 while (*sp)
209 ++sp;
210 while (sp > inspec && sp[-1] != '.')
211 --sp;
212 if (!strcasecmp(sp, "XML")) { /* assume it's a BSDF */
213 CMATRIX *cm = cm_loadBTDF((char *)inspec);
214 if (cm == NULL)
215 return(NULL);
216 dnew = rmx_from_cmatrix(cm);
217 cm_free(cm);
218 return(dnew);
219 }
220 /* else open it ourselves */
221 if ((fp = fopen(inspec, "rb")) == NULL)
222 return(NULL);
223 }
224 #ifdef getc_unlocked
225 flockfile(fp);
226 #endif
227 dinfo.nrows = dinfo.ncols = dinfo.ncomp = 0;
228 dinfo.dtype = DTascii; /* assumed w/o FORMAT */
229 dinfo.info = NULL;
230 if (getheader(fp, get_dminfo, &dinfo) < 0) {
231 fclose(fp);
232 return(NULL);
233 }
234 if ((dinfo.nrows <= 0) | (dinfo.ncols <= 0)) {
235 if (!fscnresolu(&dinfo.ncols, &dinfo.nrows, fp)) {
236 fclose(fp);
237 return(NULL);
238 }
239 if (dinfo.ncomp <= 0)
240 dinfo.ncomp = 3;
241 else if ((dinfo.dtype == DTrgbe) | (dinfo.dtype == DTxyze) &&
242 dinfo.ncomp != 3) {
243 fclose(fp);
244 return(NULL);
245 }
246 }
247 dnew = rmx_alloc(dinfo.nrows, dinfo.ncols, dinfo.ncomp);
248 if (dnew == NULL) {
249 fclose(fp);
250 return(NULL);
251 }
252 dnew->info = dinfo.info;
253 switch (dinfo.dtype) {
254 case DTascii:
255 if (!rmx_load_ascii(dnew, fp))
256 goto loaderr;
257 dnew->dtype = DTascii; /* should leave double? */
258 break;
259 case DTfloat:
260 if (!rmx_load_float(dnew, fp))
261 goto loaderr;
262 dnew->dtype = DTfloat;
263 break;
264 case DTdouble:
265 if (!rmx_load_double(dnew, fp))
266 goto loaderr;
267 dnew->dtype = DTdouble;
268 break;
269 case DTrgbe:
270 case DTxyze:
271 if (!rmx_load_rgbe(dnew, fp))
272 goto loaderr;
273 dnew->dtype = dinfo.dtype;
274 break;
275 default:
276 goto loaderr;
277 }
278 if (fp != stdin) {
279 if (inspec[0] == '!')
280 pclose(fp);
281 else
282 fclose(fp);
283 }
284 #ifdef getc_unlocked
285 else
286 funlockfile(fp);
287 #endif
288 return(dnew);
289 loaderr: /* should report error? */
290 if (inspec[0] == '!')
291 pclose(fp);
292 else
293 fclose(fp);
294 rmx_free(dnew);
295 return(NULL);
296 }
297
298 static int
299 rmx_write_ascii(const RMATRIX *rm, FILE *fp)
300 {
301 int i, j, k;
302 #ifdef _WIN32
303 _setmode(fileno(fp), _O_TEXT);
304 #endif
305 for (i = 0; i < rm->nrows; i++) {
306 for (j = 0; j < rm->ncols; j++) {
307 for (k = 0; k < rm->ncomp; k++)
308 fprintf(fp, " %.15e", rmx_lval(rm,i,j,k));
309 fputc('\t', fp);
310 }
311 fputc('\n', fp);
312 }
313 return(1);
314 }
315
316 static int
317 rmx_write_float(const RMATRIX *rm, FILE *fp)
318 {
319 int i, j, k;
320 float val[100];
321
322 if (rm->ncomp > 100) {
323 fputs("Unsupported # components in rmx_write_float()\n", stderr);
324 exit(1);
325 }
326 for (i = 0; i < rm->nrows; i++)
327 for (j = 0; j < rm->ncols; j++) {
328 for (k = rm->ncomp; k--; )
329 val[k] = (float)rmx_lval(rm,i,j,k);
330 if (fwrite(val, sizeof(val[0]), rm->ncomp, fp) != rm->ncomp)
331 return(0);
332 }
333 return(1);
334 }
335
336 static int
337 rmx_write_double(const RMATRIX *rm, FILE *fp)
338 {
339 int i, j, k;
340 double val[100];
341
342 if (rm->ncomp > 100) {
343 fputs("Unsupported # components in rmx_write_double()\n", stderr);
344 exit(1);
345 }
346 for (i = 0; i < rm->nrows; i++)
347 for (j = 0; j < rm->ncols; j++) {
348 for (k = rm->ncomp; k--; )
349 val[k] = rmx_lval(rm,i,j,k);
350 if (fwrite(val, sizeof(val[0]), rm->ncomp, fp) != rm->ncomp)
351 return(0);
352 }
353 return(1);
354 }
355
356 static int
357 rmx_write_rgbe(const RMATRIX *rm, FILE *fp)
358 {
359 COLOR *scan = (COLOR *)malloc(sizeof(COLOR)*rm->ncols);
360 int i, j;
361
362 if (scan == NULL)
363 return(0);
364 for (i = 0; i < rm->nrows; i++) {
365 for (j = rm->ncols; j--; )
366 setcolor(scan[j], rmx_lval(rm,i,j,0),
367 rmx_lval(rm,i,j,1),
368 rmx_lval(rm,i,j,2) );
369 if (fwritescan(scan, rm->ncols, fp) < 0) {
370 free(scan);
371 return(0);
372 }
373 }
374 free(scan);
375 return(1);
376 }
377
378 /* Write matrix to file type indicated by dtype */
379 int
380 rmx_write(const RMATRIX *rm, int dtype, FILE *fp)
381 {
382 RMATRIX *mydm = NULL;
383 int ok = 1;
384
385 if ((rm == NULL) | (fp == NULL))
386 return(0);
387 /* complete header */
388 if (rm->info)
389 fputs(rm->info, fp);
390 if (dtype == DTfromHeader)
391 dtype = rm->dtype;
392 else if ((dtype == DTrgbe) & (rm->dtype == DTxyze))
393 dtype = DTxyze;
394 else if ((dtype == DTxyze) & (rm->dtype == DTrgbe))
395 dtype = DTrgbe;
396 if ((dtype != DTrgbe) & (dtype != DTxyze)) {
397 fprintf(fp, "NROWS=%d\n", rm->nrows);
398 fprintf(fp, "NCOLS=%d\n", rm->ncols);
399 fprintf(fp, "NCOMP=%d\n", rm->ncomp);
400 } else if (rm->ncomp != 3) { /* wrong # components? */
401 double cmtx[3];
402 if (rm->ncomp != 1) /* only convert grayscale */
403 return(0);
404 cmtx[0] = cmtx[1] = cmtx[2] = 1;
405 mydm = rmx_transform(rm, 3, cmtx);
406 if (mydm == NULL)
407 return(0);
408 rm = mydm;
409 }
410 fputformat((char *)cm_fmt_id[dtype], fp);
411 fputc('\n', fp);
412 switch (dtype) { /* write data */
413 case DTascii:
414 ok = rmx_write_ascii(rm, fp);
415 break;
416 case DTfloat:
417 ok = rmx_write_float(rm, fp);
418 break;
419 case DTdouble:
420 ok = rmx_write_double(rm, fp);
421 break;
422 case DTrgbe:
423 case DTxyze:
424 fprtresolu(rm->ncols, rm->nrows, fp);
425 ok = rmx_write_rgbe(rm, fp);
426 break;
427 default:
428 return(0);
429 }
430 ok &= (fflush(fp) == 0);
431 rmx_free(mydm);
432 return(ok);
433 }
434
435 /* Allocate and assign square identity matrix with n components */
436 RMATRIX *
437 rmx_identity(const int dim, const int n)
438 {
439 RMATRIX *rid = rmx_alloc(dim, dim, n);
440 int i, k;
441
442 if (rid == NULL)
443 return(NULL);
444 memset(rid->mtx, 0, sizeof(rid->mtx[0])*n*dim*dim);
445 for (i = dim; i--; )
446 for (k = n; k--; )
447 rmx_lval(rid,i,i,k) = 1;
448 return(rid);
449 }
450
451 /* Duplicate the given matrix */
452 RMATRIX *
453 rmx_copy(const RMATRIX *rm)
454 {
455 RMATRIX *dnew;
456
457 if (rm == NULL)
458 return(NULL);
459 dnew = rmx_alloc(rm->nrows, rm->ncols, rm->ncomp);
460 if (dnew == NULL)
461 return(NULL);
462 rmx_addinfo(dnew, rm->info);
463 dnew->dtype = rm->dtype;
464 memcpy(dnew->mtx, rm->mtx,
465 sizeof(rm->mtx[0])*rm->ncomp*rm->nrows*rm->ncols);
466 return(dnew);
467 }
468
469 /* Allocate and assign transposed matrix */
470 RMATRIX *
471 rmx_transpose(const RMATRIX *rm)
472 {
473 RMATRIX *dnew;
474 int i, j, k;
475
476 if (rm == NULL)
477 return(0);
478 dnew = rmx_alloc(rm->ncols, rm->nrows, rm->ncomp);
479 if (dnew == NULL)
480 return(NULL);
481 if (rm->info) {
482 rmx_addinfo(dnew, rm->info);
483 rmx_addinfo(dnew, "Transposed rows and columns\n");
484 }
485 dnew->dtype = rm->dtype;
486 for (i = dnew->nrows; i--; )
487 for (j = dnew->ncols; j--; )
488 for (k = dnew->ncomp; k--; )
489 rmx_lval(dnew,i,j,k) = rmx_lval(rm,j,i,k);
490 return(dnew);
491 }
492
493 /* Multiply (concatenate) two matrices and allocate the result */
494 RMATRIX *
495 rmx_multiply(const RMATRIX *m1, const RMATRIX *m2)
496 {
497 RMATRIX *mres;
498 int i, j, k, h;
499
500 if ((m1 == NULL) | (m2 == NULL) ||
501 (m1->ncomp != m2->ncomp) | (m1->ncols != m2->nrows))
502 return(NULL);
503 mres = rmx_alloc(m1->nrows, m2->ncols, m1->ncomp);
504 if (mres == NULL)
505 return(NULL);
506 i = rmx_newtype(m1->dtype, m2->dtype);
507 if (i)
508 mres->dtype = i;
509 else
510 rmx_addinfo(mres, rmx_mismatch_warn);
511 for (i = mres->nrows; i--; )
512 for (j = mres->ncols; j--; )
513 for (k = mres->ncomp; k--; ) {
514 long double d = 0;
515 for (h = m1->ncols; h--; )
516 d += (long double)rmx_lval(m1,i,h,k) *
517 (long double)rmx_lval(m2,h,j,k);
518 rmx_lval(mres,i,j,k) = (double)d;
519 }
520 return(mres);
521 }
522
523 /* Sum second matrix into first, applying scale factor beforehand */
524 int
525 rmx_sum(RMATRIX *msum, const RMATRIX *madd, const double sf[])
526 {
527 double *mysf = NULL;
528 int i, j, k;
529
530 if ((msum == NULL) | (madd == NULL) ||
531 (msum->nrows != madd->nrows) |
532 (msum->ncols != madd->ncols) |
533 (msum->ncomp != madd->ncomp))
534 return(0);
535 if (sf == NULL) {
536 mysf = (double *)malloc(sizeof(double)*msum->ncomp);
537 if (mysf == NULL)
538 return(0);
539 for (k = msum->ncomp; k--; )
540 mysf[k] = 1;
541 sf = mysf;
542 }
543 i = rmx_newtype(msum->dtype, madd->dtype);
544 if (i)
545 msum->dtype = i;
546 else
547 rmx_addinfo(msum, rmx_mismatch_warn);
548 for (i = msum->nrows; i--; )
549 for (j = msum->ncols; j--; )
550 for (k = msum->ncomp; k--; )
551 rmx_lval(msum,i,j,k) += sf[k] * rmx_lval(madd,i,j,k);
552
553 free(mysf);
554 return(1);
555 }
556
557 /* Scale the given matrix by the indicated scalar component vector */
558 int
559 rmx_scale(RMATRIX *rm, const double sf[])
560 {
561 int i, j, k;
562
563 if ((rm == NULL) | (sf == NULL))
564 return(0);
565 for (i = rm->nrows; i--; )
566 for (j = rm->ncols; j--; )
567 for (k = rm->ncomp; k--; )
568 rmx_lval(rm,i,j,k) *= sf[k];
569
570 return(1);
571 }
572
573 /* Allocate new matrix and apply component transformation */
574 RMATRIX *
575 rmx_transform(const RMATRIX *msrc, int n, const double cmat[])
576 {
577 int i, j, ks, kd;
578 RMATRIX *dnew;
579
580 if ((msrc == NULL) | (n <= 0) | (cmat == NULL))
581 return(NULL);
582 dnew = rmx_alloc(msrc->nrows, msrc->ncols, n);
583 if (dnew == NULL)
584 return(NULL);
585 dnew->dtype = msrc->dtype;
586 for (i = dnew->nrows; i--; )
587 for (j = dnew->ncols; j--; )
588 for (kd = dnew->ncomp; kd--; ) {
589 double d = 0;
590 for (ks = msrc->ncomp; ks--; )
591 d += cmat[kd*msrc->ncomp + ks] * rmx_lval(msrc,i,j,ks);
592 rmx_lval(dnew,i,j,kd) = d;
593 }
594 return(dnew);
595 }
596
597 /* Convert a color matrix to newly allocated RMATRIX buffer */
598 RMATRIX *
599 rmx_from_cmatrix(const CMATRIX *cm)
600 {
601 int i, j;
602 RMATRIX *dnew;
603
604 if (cm == NULL)
605 return(NULL);
606 dnew = rmx_alloc(cm->nrows, cm->ncols, 3);
607 if (dnew == NULL)
608 return(NULL);
609 dnew->dtype = DTfloat;
610 for (i = dnew->nrows; i--; )
611 for (j = dnew->ncols; j--; ) {
612 const COLORV *cv = cm_lval(cm,i,j);
613 rmx_lval(dnew,i,j,0) = cv[0];
614 rmx_lval(dnew,i,j,1) = cv[1];
615 rmx_lval(dnew,i,j,2) = cv[2];
616 }
617 return(dnew);
618 }
619
620 /* Convert general matrix to newly allocated CMATRIX buffer */
621 CMATRIX *
622 cm_from_rmatrix(const RMATRIX *rm)
623 {
624 int i, j;
625 CMATRIX *cnew;
626
627 if (rm == NULL || rm->ncomp != 3)
628 return(NULL);
629 cnew = cm_alloc(rm->nrows, rm->ncols);
630 if (cnew == NULL)
631 return(NULL);
632 for (i = cnew->nrows; i--; )
633 for (j = cnew->ncols; j--; ) {
634 COLORV *cv = cm_lval(cnew,i,j);
635 cv[0] = (COLORV)rmx_lval(rm,i,j,0);
636 cv[1] = (COLORV)rmx_lval(rm,i,j,1);
637 cv[2] = (COLORV)rmx_lval(rm,i,j,2);
638 }
639 return(cnew);
640 }