GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/formatVTK.c Lines: 1 245 0.4 %
Date: 2017-05-26 Branches: 0 203 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "nrrd.h"
25
#include "privateNrrd.h"
26
27
#define MAGIC1 "# vtk DataFile Version 1.0"
28
#define MAGIC2 "# vtk DataFile Version 2.0"
29
#define MAGIC3 "# vtk DataFile Version 3.0"
30
31
int
32
_nrrdFormatVTK_available(void) {
33
34
4
  return AIR_TRUE;
35
}
36
37
int
38
_nrrdFormatVTK_nameLooksLike(const char *fname) {
39
40
  return airEndsWith(fname, NRRD_EXT_VTK);
41
}
42
43
int
44
_nrrdFormatVTK_fitsInto(const Nrrd *nrrd, const NrrdEncoding *encoding,
45
                        int useBiff) {
46
  static const char me[]="_nrrdFormatVTK_fitsInto";
47
48
  if (!( nrrd && encoding )) {
49
    biffMaybeAddf(useBiff, NRRD, "%s: got NULL nrrd (%p) or encoding (%p)",
50
                  me, AIR_CVOIDP(nrrd), AIR_CVOIDP(encoding));
51
    return AIR_FALSE;
52
  }
53
  if (!( nrrdEncodingRaw == encoding || nrrdEncodingAscii == encoding)) {
54
    biffMaybeAddf(useBiff, NRRD, "%s: encoding can only be %s or %s", me,
55
                  nrrdEncodingRaw->name, nrrdEncodingAscii->name);
56
    return AIR_FALSE;
57
  }
58
  if (!( nrrdTypeUChar == nrrd->type
59
         || nrrdTypeChar == nrrd->type
60
         || nrrdTypeUShort == nrrd->type
61
         || nrrdTypeShort == nrrd->type
62
         || nrrdTypeUInt == nrrd->type
63
         || nrrdTypeInt == nrrd->type
64
         || nrrdTypeFloat == nrrd->type
65
         || nrrdTypeDouble == nrrd->type )) {
66
    biffMaybeAddf(useBiff, NRRD,
67
                  "%s: type %s doesn't fit in VTK (as currently implemented)",
68
                  me, airEnumStr(nrrdType, nrrd->type));
69
    return AIR_FALSE;
70
  }
71
  if (!( 3 == nrrd->dim
72
         || (4 == nrrd->dim && 3 == nrrd->axis[0].size)
73
         || (4 == nrrd->dim && 9 == nrrd->axis[0].size) )) {
74
    biffMaybeAddf(useBiff, NRRD, "%s: nrrd didn't look like a volume of "
75
                  "scalars, vectors, or matrices", me);
76
    return AIR_FALSE;
77
  }
78
  return AIR_TRUE;
79
}
80
81
int
82
_nrrdFormatVTK_contentStartsLike(NrrdIoState *nio) {
83
84
  return (!strcmp(MAGIC1, nio->line)
85
          || !strcmp(MAGIC2, nio->line)
86
          || !strcmp(MAGIC3, nio->line));
87
}
88
89
int
90
_nrrdFormatVTK_read(FILE *file, Nrrd *nrrd, NrrdIoState *nio) {
91
  static const char me[]="_nrrdReadVTK";
92
  char *three[3];
93
  int sx, sy, sz, ret, N;
94
  double xm=0.0, ym=0.0, zm=0.0, xs=1.0, ys=1.0, zs=1.0;
95
  airArray *mop;
96
  unsigned int llen;
97
98
  if (!_nrrdFormatVTK_contentStartsLike(nio)) {
99
    biffAddf(NRRD, "%s: this doesn't look like a %s file", me,
100
             nrrdFormatVTK->name);
101
    return 1;
102
  }
103
104
#define GETLINE(what)                                        \
105
  do {                                                       \
106
    ret = _nrrdOneLine(&llen, nio, file);                    \
107
  } while (!ret && (1 == llen));                             \
108
  if (ret || !llen) {                                        \
109
    biffAddf(NRRD, "%s: couldn't get " #what " line", me);   \
110
    return 1;                                                \
111
  }
112
113
  /* read in content */
114
  GETLINE(content);
115
  if (strcmp(NRRD_UNKNOWN, nio->line)) {
116
    if (!(nrrd->content = airStrdup(nio->line))) {
117
      biffAddf(NRRD, "%s: couldn't read or copy content string", me);
118
      return 1;
119
    }
120
  }
121
  GETLINE(encoding); airToUpper(nio->line);
122
  if (!strcmp("ASCII", nio->line)) {
123
    nio->encoding = nrrdEncodingAscii;
124
  } else if (!strcmp("BINARY", nio->line)) {
125
    nio->encoding = nrrdEncodingRaw;
126
  } else {
127
    biffAddf(NRRD, "%s: encoding \"%s\" wasn't \"ASCII\" or \"BINARY\"",
128
             me, nio->line);
129
    return 1;
130
  }
131
  GETLINE(DATASET); airToUpper(nio->line);
132
  if (!strstr(nio->line, "STRUCTURED_POINTS")) {
133
    biffAddf(NRRD,
134
             "%s: sorry, only STRUCTURED_POINTS data is nrrd-ready", me);
135
    return 1;
136
  }
137
  GETLINE(DIMENSIONS); airToUpper(nio->line);
138
  if (!strstr(nio->line, "DIMENSIONS")
139
      || 3 != sscanf(nio->line, "DIMENSIONS %d %d %d", &sx, &sy, &sz)) {
140
    biffAddf(NRRD, "%s: couldn't parse DIMENSIONS line (\"%s\")",
141
             me, nio->line);
142
    return 1;
143
  }
144
  GETLINE(next); airToUpper(nio->line);
145
  while (!strstr(nio->line, "POINT_DATA")) {
146
    if (strstr(nio->line, "ORIGIN")) {
147
      if (3 != sscanf(nio->line, "ORIGIN %lf %lf %lf", &xm, &ym, &zm)) {
148
        biffAddf(NRRD, "%s: couldn't parse ORIGIN line (\"%s\")",
149
                 me, nio->line);
150
        return 1;
151
      }
152
    } else if (strstr(nio->line, "SPACING")) {
153
      if (3 != sscanf(nio->line, "SPACING %lf %lf %lf",
154
                      &xs, &ys, &zs)) {
155
        biffAddf(NRRD, "%s: couldn't parse SPACING line (\"%s\")",
156
                 me, nio->line);
157
        return 1;
158
      }
159
    } else if (strstr(nio->line, "ASPECT_RATIO")) {
160
      if (3 != sscanf(nio->line, "ASPECT_RATIO %lf %lf %lf",
161
                      &xs, &ys, &zs)) {
162
        biffAddf(NRRD, "%s: couldn't parse ASPECT_RATIO line (\"%s\")",
163
                 me, nio->line);
164
        return 1;
165
      }
166
    }
167
    GETLINE(next); airToUpper(nio->line);
168
  }
169
  if (1 != sscanf(nio->line, "POINT_DATA %d", &N)) {
170
    biffAddf(NRRD, "%s: couldn't parse POINT_DATA line (\"%s\")",
171
             me, nio->line);
172
    return 1;
173
  }
174
  if (N != sx*sy*sz) {
175
    biffAddf(NRRD,
176
             "%s: product of sizes (%d*%d*%d == %d) != # elements (%d)",
177
             me, sx, sy, sz, sx*sy*sz, N);
178
    return 1;
179
  }
180
  GETLINE(attribute declaration);
181
  mop = airMopNew();
182
  if (3 != airParseStrS(three, nio->line, AIR_WHITESPACE, 3, AIR_FALSE)) {
183
    biffAddf(NRRD,
184
             "%s: didn't see three words in attribute declaration \"%s\"",
185
             me, nio->line);
186
    return 1;
187
  }
188
  airMopAdd(mop, three[0], airFree, airMopAlways);
189
  airMopAdd(mop, three[1], airFree, airMopAlways);
190
  airMopAdd(mop, three[2], airFree, airMopAlways);
191
  airToLower(three[2]);
192
  if (!strcmp(three[2], "bit")) {
193
    if (nrrdEncodingAscii == nio->encoding) {
194
      fprintf(stderr, "%s: WARNING: \"bit\"-type data will be read in as "
195
              "unsigned char\n", me);
196
      nrrd->type = nrrdTypeUChar;
197
    } else {
198
      biffAddf(NRRD, "%s: can't read in \"bit\"-type data as BINARY", me);
199
      return 1;
200
    }
201
  } else if (!strcmp(three[2], "unsigned_char")) {
202
    nrrd->type = nrrdTypeUChar;
203
  } else if (!strcmp(three[2], "char")) {
204
    nrrd->type = nrrdTypeChar;
205
  } else if (!strcmp(three[2], "unsigned_short")) {
206
    nrrd->type = nrrdTypeUShort;
207
  } else if (!strcmp(three[2], "short")) {
208
    nrrd->type = nrrdTypeShort;
209
  } else if (!strcmp(three[2], "unsigned_int")) {
210
    nrrd->type = nrrdTypeUInt;
211
  } else if (!strcmp(three[2], "int")) {
212
    nrrd->type = nrrdTypeInt;
213
  } else if (!strcmp(three[2], "float")) {
214
    nrrd->type = nrrdTypeFloat;
215
  } else if (!strcmp(three[2], "double")) {
216
    nrrd->type = nrrdTypeDouble;
217
  } else {
218
    /* "unsigned_long" and "long" fall in here- I don't know what
219
       the VTK people mean by these types, since always mean different
220
       things on 32-bit versus 64-bit architectures */
221
    biffAddf(NRRD, "%s: type \"%s\" not recognized", me, three[2]);
222
    airMopError(mop); return 1;
223
  }
224
  airToUpper(three[0]);
225
  if (!strncmp("SCALARS", three[0], strlen("SCALARS"))) {
226
    GETLINE(LOOKUP_TABLE); airToUpper(nio->line);
227
    if (strcmp(nio->line, "LOOKUP_TABLE DEFAULT")) {
228
      biffAddf(NRRD,
229
               "%s: sorry, can only deal with default LOOKUP_TABLE", me);
230
      airMopError(mop); return 1;
231
    }
232
    nrrd->dim = 3;
233
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize,
234
                       AIR_CAST(size_t, sx),
235
                       AIR_CAST(size_t, sy),
236
                       AIR_CAST(size_t, sz));
237
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, xs, ys, zs);
238
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, xm, ym, zm);
239
  } else if (!strncmp("VECTORS", three[0], strlen("VECTORS"))) {
240
    nrrd->dim = 4;
241
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize,
242
                       AIR_CAST(size_t, 3),
243
                       AIR_CAST(size_t, sx),
244
                       AIR_CAST(size_t, sy),
245
                       AIR_CAST(size_t, sz));
246
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, AIR_NAN, xs, ys, zs);
247
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, AIR_NAN, xm, ym, zm);
248
    nrrd->axis[0].kind = nrrdKind3Vector;
249
  } else if (!strncmp("TENSORS", three[0], strlen("TENSORS"))) {
250
    nrrd->dim = 4;
251
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize,
252
                       AIR_CAST(size_t, 9),
253
                       AIR_CAST(size_t, sx),
254
                       AIR_CAST(size_t, sy),
255
                       AIR_CAST(size_t, sz));
256
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, AIR_NAN, xs, ys, zs);
257
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, AIR_NAN, xm, ym, zm);
258
    nrrd->axis[0].kind = nrrdKind3DMatrix;
259
  } else {
260
    biffAddf(NRRD,
261
             "%s: sorry, can only deal with SCALARS, VECTORS, and TENSORS "
262
             "currently, so couldn't parse attribute declaration \"%s\"",
263
             me, nio->line);
264
    airMopError(mop); return 1;
265
  }
266
  if (!nio->skipData) {
267
    if (_nrrdCalloc(nrrd, nio, file)) {
268
      biffAddf(NRRD, "%s: couldn't allocate memory for data", me);
269
      return 1;
270
    }
271
    if (nio->encoding->read(file, nrrd->data, nrrdElementNumber(nrrd),
272
                            nrrd, nio)) {
273
      biffAddf(NRRD, "%s:", me);
274
      return 1;
275
    }
276
    if (1 < nrrdElementSize(nrrd)
277
        && nio->encoding->endianMatters
278
        && airMyEndian() != airEndianBig) {
279
      /* encoding exposes endianness, and its big, but we aren't */
280
      nrrdSwapEndian(nrrd);
281
    }
282
  } else {
283
    nrrd->data = NULL;
284
  }
285
286
  airMopOkay(mop);
287
  return 0;
288
}
289
290
/* this strongly assumes that nrrdFitsInFormat() was true */
291
int
292
_nrrdFormatVTK_write(FILE *file, const Nrrd *_nrrd, NrrdIoState *nio) {
293
  static const char me[]="_nrrdFormatVTK_write";
294
  int i, sx, sy, sz, sax;
295
  double xs, ys, zs, xm, ym, zm;
296
  char type[AIR_STRLEN_MED], name[AIR_STRLEN_SMALL];
297
  Nrrd *nrrd;
298
  airArray *mop;
299
300
  /* HEY: should this copy be done more conservatively */
301
  mop = airMopNew();
302
  airMopAdd(mop, nrrd=nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
303
  if (nrrdCopy(nrrd, _nrrd)) {
304
    biffAddf(NRRD, "%s: couldn't make private copy", me);
305
    airMopError(mop); return 1;
306
  }
307
  if (!( 3 == nrrd->dim ||
308
         (4 == nrrd->dim && (3 == nrrd->axis[0].size ||
309
                             9 == nrrd->axis[0].size)) )) {
310
    biffAddf(NRRD, "%s: doesn't seem to be scalar, vector, or matrix", me);
311
    airMopError(mop); return 1;
312
  }
313
  sax = nrrd->dim - 3;
314
  xs = nrrd->axis[sax+0].spacing;
315
  ys = nrrd->axis[sax+1].spacing;
316
  zs = nrrd->axis[sax+2].spacing;
317
  if (!( AIR_EXISTS(xs) && AIR_EXISTS(ys) && AIR_EXISTS(zs) )) {
318
    xs = ys = zs = 1.0;
319
  }
320
  xm = nrrd->axis[sax+0].min;
321
  ym = nrrd->axis[sax+1].min;
322
  zm = nrrd->axis[sax+2].min;
323
  if (!( AIR_EXISTS(xm) && AIR_EXISTS(ym) && AIR_EXISTS(zm) )) {
324
    xm = ym = zm = 0.0;
325
  }
326
  sx = AIR_CAST(int, nrrd->axis[sax+0].size);
327
  sy = AIR_CAST(int, nrrd->axis[sax+1].size);
328
  sz = AIR_CAST(int, nrrd->axis[sax+2].size);
329
330
  switch(nrrd->type) {
331
  case nrrdTypeUChar:
332
    strcpy(type, "unsigned_char");
333
    break;
334
  case nrrdTypeChar:
335
    strcpy(type, "char");
336
    break;
337
  case nrrdTypeUShort:
338
    strcpy(type, "unsigned_short");
339
    break;
340
  case nrrdTypeShort:
341
    strcpy(type, "short");
342
    break;
343
  case nrrdTypeUInt:
344
    strcpy(type, "unsigned_int");
345
    break;
346
  case nrrdTypeInt:
347
    strcpy(type, "int");
348
    break;
349
  case nrrdTypeFloat:
350
    strcpy(type, "float");
351
    break;
352
  case nrrdTypeDouble:
353
    strcpy(type, "double");
354
    break;
355
  default:
356
    biffAddf(NRRD, "%s: can't put %s-type nrrd into VTK", me,
357
             airEnumStr(nrrdType, nrrd->type));
358
    airMopError(mop); return 1;
359
  }
360
  fprintf(file, "%s\n", MAGIC3);
361
  /* there is a file-format-imposed limit on the length of the "content" */
362
  if (nrrd->content) {
363
    /* when the "250" below was previously "255", vtk didn't deal */
364
    for (i=0; i<=250 && nrrd->content[i]; i++) {
365
      fputc(nrrd->content[i], file);
366
    }
367
    fputc('\n', file);
368
  } else {
369
    fprintf(file, NRRD_UNKNOWN "\n");
370
  }
371
  if (nrrdEncodingRaw == nio->encoding) {
372
    fprintf(file, "BINARY\n");
373
  } else {
374
    fprintf(file, "ASCII\n");
375
  }
376
  fprintf(file, "DATASET STRUCTURED_POINTS\n");
377
  fprintf(file, "DIMENSIONS %d %d %d\n", sx, sy, sz);
378
  fprintf(file, "ORIGIN %g %g %g\n", xm, ym, zm);
379
  fprintf(file, "SPACING %g %g %g\n", xs, ys, zs);
380
  fprintf(file, "POINT_DATA %d\n", sx*sy*sz);
381
  airSrandMT(AIR_CAST(unsigned int, airTime()));
382
  sprintf(name, "nrrd%05d", airRandInt(100000));
383
  if (3 == nrrd->dim) {
384
    fprintf(file, "SCALARS %s %s\n", name, type);
385
    fprintf(file, "LOOKUP_TABLE default\n");
386
  } else {
387
    /* 4 == nrrd->dim */
388
    if (3 == nrrd->axis[0].size) {
389
      fprintf(file, "VECTORS %s %s\n", name, type);
390
    } else {
391
      fprintf(file, "TENSORS %s %s\n", name, type);
392
    }
393
  }
394
  if (1 < nrrdElementSize(nrrd)
395
      && nio->encoding->endianMatters
396
      && airMyEndian() != airEndianBig) {
397
    /* encoding exposes endianness, and we're not big, as req.d by VTK */
398
    nrrdSwapEndian(nrrd);
399
  }
400
  if (nio->encoding->write(file, nrrd->data, nrrdElementNumber(nrrd),
401
                           nrrd, nio)) {
402
    biffAddf(NRRD, "%s:", me);
403
    airMopError(mop); return 1;
404
  }
405
406
  airMopOkay(mop);
407
  return 0;
408
}
409
410
const NrrdFormat
411
_nrrdFormatVTK = {
412
  "VTK",
413
  AIR_FALSE,  /* isImage */
414
  AIR_TRUE,   /* readable */
415
  AIR_FALSE,  /* usesDIO */
416
  _nrrdFormatVTK_available,
417
  _nrrdFormatVTK_nameLooksLike,
418
  _nrrdFormatVTK_fitsInto,
419
  _nrrdFormatVTK_contentStartsLike,
420
  _nrrdFormatVTK_read,
421
  _nrrdFormatVTK_write
422
};
423
424
const NrrdFormat *const
425
nrrdFormatVTK = &_nrrdFormatVTK;