GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
/* ------------------------------------------------------------ */ |
||
28 |
|||
29 |
void |
||
30 |
_nrrdAxisInfoInit(NrrdAxisInfo *axis) { |
||
31 |
int dd; |
||
32 |
|||
33 |
✓✗ | 78640 |
if (axis) { |
34 |
39320 |
axis->size = 0; |
|
35 |
39320 |
axis->spacing = axis->thickness = AIR_NAN; |
|
36 |
39320 |
axis->min = axis->max = AIR_NAN; |
|
37 |
✓✓ | 707760 |
for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) { |
38 |
314560 |
axis->spaceDirection[dd] = AIR_NAN; |
|
39 |
} |
||
40 |
39320 |
axis->center = nrrdCenterUnknown; |
|
41 |
39320 |
axis->kind = nrrdKindUnknown; |
|
42 |
39320 |
axis->label = (char *)airFree(axis->label); |
|
43 |
39320 |
axis->units = (char *)airFree(axis->units); |
|
44 |
39320 |
} |
|
45 |
39320 |
} |
|
46 |
|||
47 |
void |
||
48 |
_nrrdAxisInfoNewInit(NrrdAxisInfo *axis) { |
||
49 |
|||
50 |
✓✗ | 19456 |
if (axis) { |
51 |
9728 |
axis->label = NULL; |
|
52 |
9728 |
axis->units = NULL; |
|
53 |
9728 |
_nrrdAxisInfoInit(axis); |
|
54 |
9728 |
} |
|
55 |
9728 |
} |
|
56 |
|||
57 |
/* ------------------------------------------------------------ */ |
||
58 |
|||
59 |
/* |
||
60 |
******** nrrdKindIsDomain |
||
61 |
** |
||
62 |
** returns non-zero for kinds (from nrrdKind* enum) that are domain |
||
63 |
** axes, or independent variable axes, or resample-able axes, all |
||
64 |
** different ways of describing the same thing |
||
65 |
*/ |
||
66 |
int |
||
67 |
nrrdKindIsDomain(int kind) { |
||
68 |
|||
69 |
168 |
return (nrrdKindDomain == kind |
|
70 |
✓✓ | 56 |
|| nrrdKindSpace == kind |
71 |
88 |
|| nrrdKindTime == kind); |
|
72 |
} |
||
73 |
|||
74 |
/* |
||
75 |
******** nrrdKindSize |
||
76 |
** |
||
77 |
** returns suggested size (length) of an axis with the given kind, or, |
||
78 |
** 0 if either (1) there is no suggested size because the axis is the |
||
79 |
** kind of an independent or domain variable or (2) the kind is invalid |
||
80 |
*/ |
||
81 |
unsigned int |
||
82 |
nrrdKindSize(int kind) { |
||
83 |
static const char me[]="nrrdKindSize"; |
||
84 |
unsigned int ret; |
||
85 |
|||
86 |
✓✓ | 20170 |
if (!( AIR_IN_OP(nrrdKindUnknown, kind, nrrdKindLast) )) { |
87 |
/* they gave us invalid or unknown kind */ |
||
88 |
3875 |
return 0; |
|
89 |
} |
||
90 |
|||
91 |
✗✗✗✗ ✗✗✗✓ ✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✓✓ ✗✗✗ |
6210 |
switch (kind) { |
92 |
case nrrdKindDomain: |
||
93 |
case nrrdKindSpace: |
||
94 |
case nrrdKindTime: |
||
95 |
case nrrdKindList: |
||
96 |
case nrrdKindPoint: |
||
97 |
case nrrdKindVector: |
||
98 |
case nrrdKindCovariantVector: |
||
99 |
case nrrdKindNormal: |
||
100 |
ret = 0; |
||
101 |
6090 |
break; |
|
102 |
case nrrdKindStub: |
||
103 |
case nrrdKindScalar: |
||
104 |
ret = 1; |
||
105 |
8 |
break; |
|
106 |
case nrrdKindComplex: |
||
107 |
case nrrdKind2Vector: |
||
108 |
ret = 2; |
||
109 |
break; |
||
110 |
case nrrdKind3Color: |
||
111 |
case nrrdKindRGBColor: |
||
112 |
case nrrdKindHSVColor: |
||
113 |
case nrrdKindXYZColor: |
||
114 |
ret = 3; |
||
115 |
break; |
||
116 |
case nrrdKind4Color: |
||
117 |
case nrrdKindRGBAColor: |
||
118 |
ret = 4; |
||
119 |
break; |
||
120 |
case nrrdKind3Vector: |
||
121 |
case nrrdKind3Normal: |
||
122 |
ret = 3; |
||
123 |
break; |
||
124 |
case nrrdKind4Vector: |
||
125 |
case nrrdKindQuaternion: |
||
126 |
ret = 4; |
||
127 |
break; |
||
128 |
case nrrdKind2DSymMatrix: |
||
129 |
ret = 3; |
||
130 |
break; |
||
131 |
case nrrdKind2DMaskedSymMatrix: |
||
132 |
ret = 4; |
||
133 |
break; |
||
134 |
case nrrdKind2DMatrix: |
||
135 |
ret = 4; |
||
136 |
break; |
||
137 |
case nrrdKind2DMaskedMatrix: |
||
138 |
ret = 5; |
||
139 |
break; |
||
140 |
case nrrdKind3DSymMatrix: |
||
141 |
ret = 6; |
||
142 |
16 |
break; |
|
143 |
case nrrdKind3DMaskedSymMatrix: |
||
144 |
ret = 7; |
||
145 |
96 |
break; |
|
146 |
case nrrdKind3DMatrix: |
||
147 |
ret = 9; |
||
148 |
break; |
||
149 |
case nrrdKind3DMaskedMatrix: |
||
150 |
ret = 10; |
||
151 |
break; |
||
152 |
default: |
||
153 |
fprintf(stderr, "%s: PANIC: nrrdKind %d not implemented!\n", me, kind); |
||
154 |
ret = UINT_MAX; |
||
155 |
} |
||
156 |
|||
157 |
6210 |
return ret; |
|
158 |
10085 |
} |
|
159 |
|||
160 |
/* |
||
161 |
** _nrrdKindAltered: |
||
162 |
** |
||
163 |
** implements logic for how kind should be updated when samples |
||
164 |
** along the axis are altered |
||
165 |
*/ |
||
166 |
int |
||
167 |
_nrrdKindAltered(int kindIn, int resampling) { |
||
168 |
int kindOut; |
||
169 |
|||
170 |
✗✓ | 112 |
if (nrrdStateKindNoop) { |
171 |
kindOut = nrrdKindUnknown; |
||
172 |
/* HEY: setting the kindOut to unknown is arguably not a no-op. |
||
173 |
It is more like pointedly and stubbornly simplistic. So maybe |
||
174 |
nrrdStateKindNoop could be renamed .. */ |
||
175 |
} else { |
||
176 |
56 |
if (nrrdKindIsDomain(kindIn) |
|
177 |
✓✓✓✓ |
88 |
|| (0 == nrrdKindSize(kindIn) && !resampling)) { |
178 |
kindOut = kindIn; |
||
179 |
32 |
} else { |
|
180 |
kindOut = nrrdKindUnknown; |
||
181 |
} |
||
182 |
} |
||
183 |
56 |
return kindOut; |
|
184 |
} |
||
185 |
|||
186 |
/* |
||
187 |
** _nrrdAxisInfoCopy |
||
188 |
** |
||
189 |
** HEY: we have a void return even though this function potentially |
||
190 |
** involves calling airStrdup!! |
||
191 |
*/ |
||
192 |
void |
||
193 |
_nrrdAxisInfoCopy(NrrdAxisInfo *dest, const NrrdAxisInfo *src, int bitflag) { |
||
194 |
int ii; |
||
195 |
|||
196 |
✓✓ | 2264 |
if (!(NRRD_AXIS_INFO_SIZE_BIT & bitflag)) { |
197 |
676 |
dest->size = src->size; |
|
198 |
676 |
} |
|
199 |
✓✗ | 1132 |
if (!(NRRD_AXIS_INFO_SPACING_BIT & bitflag)) { |
200 |
1132 |
dest->spacing = src->spacing; |
|
201 |
1132 |
} |
|
202 |
✓✗ | 1132 |
if (!(NRRD_AXIS_INFO_THICKNESS_BIT & bitflag)) { |
203 |
1132 |
dest->thickness = src->thickness; |
|
204 |
1132 |
} |
|
205 |
✓✓ | 1132 |
if (!(NRRD_AXIS_INFO_MIN_BIT & bitflag)) { |
206 |
1020 |
dest->min = src->min; |
|
207 |
1020 |
} |
|
208 |
✓✓ | 1132 |
if (!(NRRD_AXIS_INFO_MAX_BIT & bitflag)) { |
209 |
1020 |
dest->max = src->max; |
|
210 |
1020 |
} |
|
211 |
✓✗ | 1132 |
if (!(NRRD_AXIS_INFO_SPACEDIRECTION_BIT & bitflag)) { |
212 |
✓✓ | 20376 |
for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) { |
213 |
9056 |
dest->spaceDirection[ii] = src->spaceDirection[ii]; |
|
214 |
} |
||
215 |
} |
||
216 |
✓✗ | 1132 |
if (!(NRRD_AXIS_INFO_CENTER_BIT & bitflag)) { |
217 |
1132 |
dest->center = src->center; |
|
218 |
1132 |
} |
|
219 |
✓✗ | 1132 |
if (!(NRRD_AXIS_INFO_KIND_BIT & bitflag)) { |
220 |
1132 |
dest->kind = src->kind; |
|
221 |
1132 |
} |
|
222 |
✓✗ | 1132 |
if (!(NRRD_AXIS_INFO_LABEL_BIT & bitflag)) { |
223 |
✓✓ | 1132 |
if (dest->label != src->label) { |
224 |
4 |
dest->label = (char *)airFree(dest->label); |
|
225 |
4 |
dest->label = (char *)airStrdup(src->label); |
|
226 |
4 |
} |
|
227 |
} |
||
228 |
✓✗ | 1132 |
if (!(NRRD_AXIS_INFO_UNITS_BIT & bitflag)) { |
229 |
✗✓ | 1132 |
if (dest->units != src->units) { |
230 |
dest->units = (char *)airFree(dest->units); |
||
231 |
dest->units = (char *)airStrdup(src->units); |
||
232 |
} |
||
233 |
} |
||
234 |
|||
235 |
return; |
||
236 |
1132 |
} |
|
237 |
|||
238 |
/* |
||
239 |
******** nrrdAxisInfoCopy() |
||
240 |
** |
||
241 |
** For copying all the per-axis peripheral information. Takes a |
||
242 |
** permutation "map"; map[d] tells from which axis in input should the |
||
243 |
** output axis d copy its information. The length of this permutation |
||
244 |
** array is nout->dim. If map is NULL, the identity permutation is |
||
245 |
** assumed. If map[i]==-1 for any i in [0,dim-1], then nothing is |
||
246 |
** copied into axis i of output. The "bitflag" field controls which |
||
247 |
** per-axis fields will NOT be copied; if bitflag==0, then all fields |
||
248 |
** are copied. The value of bitflag should be |'s of NRRD_AXIS_INFO_* |
||
249 |
** defines. |
||
250 |
** |
||
251 |
** Decided to Not use Biff, since many times map will be NULL, in |
||
252 |
** which case the only error is getting a NULL nrrd, or an invalid map |
||
253 |
** permutation, which will probably be unlikely given the contexts in |
||
254 |
** which this is called. For the paranoid, the integer return value |
||
255 |
** indicates error. |
||
256 |
** |
||
257 |
** Sun Feb 27 21:12:57 EST 2005: decided to allow nout==nin, so now |
||
258 |
** use a local array of NrrdAxisInfo as buffer. |
||
259 |
*/ |
||
260 |
int |
||
261 |
nrrdAxisInfoCopy(Nrrd *nout, const Nrrd *nin, const int *axmap, int bitflag) { |
||
262 |
782 |
NrrdAxisInfo axisBuffer[NRRD_DIM_MAX]; |
|
263 |
const NrrdAxisInfo *axis; |
||
264 |
unsigned int from, axi; |
||
265 |
|||
266 |
✗✓ | 391 |
if (!(nout && nin)) { |
267 |
return 1; |
||
268 |
} |
||
269 |
✓✓ | 391 |
if (axmap) { |
270 |
✓✓ | 1552 |
for (axi=0; axi<nout->dim; axi++) { |
271 |
✓✓ | 584 |
if (-1 == axmap[axi]) { |
272 |
continue; |
||
273 |
} |
||
274 |
✓✗✗✓ |
1152 |
if (!AIR_IN_CL(0, axmap[axi], (int)nin->dim-1)) { |
275 |
return 3; |
||
276 |
} |
||
277 |
} |
||
278 |
} |
||
279 |
✗✓ | 391 |
if (nout == nin) { |
280 |
/* copy axis info to local buffer */ |
||
281 |
for (axi=0; axi<nin->dim; axi++) { |
||
282 |
_nrrdAxisInfoNewInit(axisBuffer + axi); |
||
283 |
_nrrdAxisInfoCopy(axisBuffer + axi, nin->axis + axi, bitflag); |
||
284 |
} |
||
285 |
axis = axisBuffer; |
||
286 |
} else { |
||
287 |
391 |
axis = nin->axis; |
|
288 |
} |
||
289 |
✓✓ | 3014 |
for (axi=0; axi<nout->dim; axi++) { |
290 |
✓✓✓✓ |
1700 |
if (axmap && -1 == axmap[axi]) { |
291 |
/* for this axis, we don't touch a thing */ |
||
292 |
continue; |
||
293 |
} |
||
294 |
✓✓ | 2792 |
from = axmap ? (unsigned int)axmap[axi] : axi; |
295 |
1108 |
_nrrdAxisInfoCopy(nout->axis + axi, axis + from, bitflag); |
|
296 |
1108 |
} |
|
297 |
✗✓ | 391 |
if (nout == nin) { |
298 |
/* free dynamically allocated stuff */ |
||
299 |
for (axi=0; axi<nin->dim; axi++) { |
||
300 |
_nrrdAxisInfoInit(axisBuffer + axi); |
||
301 |
} |
||
302 |
} |
||
303 |
391 |
return 0; |
|
304 |
391 |
} |
|
305 |
|||
306 |
/* |
||
307 |
******** nrrdAxisInfoSet_nva() |
||
308 |
** |
||
309 |
** Simple means of setting fields of the axis array in the nrrd. |
||
310 |
** |
||
311 |
** type to pass for third argument: |
||
312 |
** nrrdAxisInfoSize: size_t* |
||
313 |
** nrrdAxisInfoSpacing: double* |
||
314 |
** nrrdAxisInfoThickness: double* |
||
315 |
** nrrdAxisInfoMin: double* |
||
316 |
** nrrdAxisInfoMax: double* |
||
317 |
** nrrdAxisInfoSpaceDirection: double (*var)[NRRD_SPACE_DIM_MAX] |
||
318 |
** nrrdAxisInfoCenter: int* |
||
319 |
** nrrdAxisInfoKind: int* |
||
320 |
** nrrdAxisInfoLabel: char** |
||
321 |
** nrrdAxisInfoUnits: char** |
||
322 |
** |
||
323 |
** Note that in the case of nrrdAxisInfoSpaceDirection, we only access |
||
324 |
** spaceDim elements of info.V[ai] (so caller can allocate it for less |
||
325 |
** than NRRD_SPACE_DIM_MAX if they know what they're doing) |
||
326 |
*/ |
||
327 |
void |
||
328 |
nrrdAxisInfoSet_nva(Nrrd *nrrd, int axInfo, const void *_info) { |
||
329 |
_nrrdAxisInfoSetPtrs info; |
||
330 |
int exists; |
||
331 |
unsigned int ai, si, minsi; |
||
332 |
|||
333 |
1536 |
if (!( nrrd |
|
334 |
✓✗✓✗ |
2304 |
&& AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX) |
335 |
✗✓✗✓ |
1536 |
&& AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) |
336 |
768 |
&& _info )) { |
|
337 |
return; |
||
338 |
} |
||
339 |
768 |
info.P = _info; |
|
340 |
|||
341 |
✓✓ | 5656 |
for (ai=0; ai<nrrd->dim; ai++) { |
342 |
✓✗✗✓ ✓✓✓✓ ✓✗✓ |
4120 |
switch (axInfo) { |
343 |
case nrrdAxisInfoSize: |
||
344 |
1766 |
nrrd->axis[ai].size = info.ST[ai]; |
|
345 |
1766 |
break; |
|
346 |
case nrrdAxisInfoSpacing: |
||
347 |
nrrd->axis[ai].spacing = info.D[ai]; |
||
348 |
break; |
||
349 |
case nrrdAxisInfoThickness: |
||
350 |
nrrd->axis[ai].thickness = info.D[ai]; |
||
351 |
break; |
||
352 |
case nrrdAxisInfoMin: |
||
353 |
6 |
nrrd->axis[ai].min = info.D[ai]; |
|
354 |
6 |
break; |
|
355 |
case nrrdAxisInfoMax: |
||
356 |
6 |
nrrd->axis[ai].max = info.D[ai]; |
|
357 |
6 |
break; |
|
358 |
case nrrdAxisInfoSpaceDirection: |
||
359 |
/* we won't allow setting an invalid direction */ |
||
360 |
125 |
exists = AIR_EXISTS(info.V[ai][0]); |
|
361 |
125 |
minsi = nrrd->spaceDim; |
|
362 |
✓✓ | 1000 |
for (si=0; si<nrrd->spaceDim; si++) { |
363 |
375 |
nrrd->axis[ai].spaceDirection[si] = info.V[ai][si]; |
|
364 |
✗✓ | 375 |
if (exists ^ AIR_EXISTS(info.V[ai][si])) { |
365 |
minsi = 0; |
||
366 |
break; |
||
367 |
} |
||
368 |
} |
||
369 |
✓✓ | 1500 |
for (si=minsi; si<NRRD_SPACE_DIM_MAX; si++) { |
370 |
625 |
nrrd->axis[ai].spaceDirection[si] = AIR_NAN; |
|
371 |
} |
||
372 |
break; |
||
373 |
case nrrdAxisInfoCenter: |
||
374 |
122 |
nrrd->axis[ai].center = info.I[ai]; |
|
375 |
122 |
break; |
|
376 |
case nrrdAxisInfoKind: |
||
377 |
32 |
nrrd->axis[ai].kind = info.I[ai]; |
|
378 |
32 |
break; |
|
379 |
case nrrdAxisInfoLabel: |
||
380 |
3 |
nrrd->axis[ai].label = (char *)airFree(nrrd->axis[ai].label); |
|
381 |
3 |
nrrd->axis[ai].label = (char *)airStrdup(info.CP[ai]); |
|
382 |
3 |
break; |
|
383 |
case nrrdAxisInfoUnits: |
||
384 |
nrrd->axis[ai].units = (char *)airFree(nrrd->axis[ai].units); |
||
385 |
nrrd->axis[ai].units = (char *)airStrdup(info.CP[ai]); |
||
386 |
break; |
||
387 |
} |
||
388 |
} |
||
389 |
✓✓ | 768 |
if (nrrdAxisInfoSpaceDirection == axInfo) { |
390 |
✓✓ | 1076 |
for (ai=nrrd->dim; ai<NRRD_DIM_MAX; ai++) { |
391 |
✓✓ | 8982 |
for (si=0; si<NRRD_SPACE_DIM_MAX; si++) { |
392 |
3992 |
nrrd->axis[ai].spaceDirection[si] = AIR_NAN; |
|
393 |
} |
||
394 |
} |
||
395 |
} |
||
396 |
768 |
return; |
|
397 |
768 |
} |
|
398 |
|||
399 |
/* |
||
400 |
******** nrrdAxisInfoSet_va() |
||
401 |
** |
||
402 |
** var args front-end for nrrdAxisInfoSet_nva |
||
403 |
** |
||
404 |
** types to pass, one for each dimension: |
||
405 |
** nrrdAxisInfoSize: size_t |
||
406 |
** nrrdAxisInfoSpacing: double |
||
407 |
** nrrdAxisInfoThickness: double |
||
408 |
** nrrdAxisInfoMin: double |
||
409 |
** nrrdAxisInfoMax: double |
||
410 |
** nrrdAxisInfoSpaceDirection: double* |
||
411 |
** nrrdAxisInfoCenter: int |
||
412 |
** nrrdAxisInfoKind: int |
||
413 |
** nrrdAxisInfoLabel: char* |
||
414 |
** nrrdAxisInfoUnits: char* |
||
415 |
*/ |
||
416 |
void |
||
417 |
nrrdAxisInfoSet_va(Nrrd *nrrd, int axInfo, ...) { |
||
418 |
174 |
NRRD_TYPE_BIGGEST *buffer[NRRD_DIM_MAX]; |
|
419 |
_nrrdAxisInfoSetPtrs info; |
||
420 |
unsigned int ai, si; |
||
421 |
87 |
va_list ap; |
|
422 |
87 |
double *dp, svec[NRRD_DIM_MAX][NRRD_SPACE_DIM_MAX]; |
|
423 |
|||
424 |
87 |
if (!( nrrd |
|
425 |
✓✗✓✗ |
261 |
&& AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX) |
426 |
✗✓ | 87 |
&& AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) )) { |
427 |
return; |
||
428 |
} |
||
429 |
|||
430 |
87 |
info.P = buffer; |
|
431 |
87 |
va_start(ap, axInfo); |
|
432 |
✓✓ | 740 |
for (ai=0; ai<nrrd->dim; ai++) { |
433 |
✓✓✗✓ ✗✗✗✗ ✓✗✓ |
566 |
switch (axInfo) { |
434 |
case nrrdAxisInfoSize: |
||
435 |
✓✗ | 12 |
info.ST[ai] = va_arg(ap, size_t); |
436 |
/* |
||
437 |
printf("!%s: got int[%d] = %d\n", "nrrdAxisInfoSet", d, info.I[ai]); |
||
438 |
*/ |
||
439 |
4 |
break; |
|
440 |
case nrrdAxisInfoSpaceDirection: |
||
441 |
✓✗ | 366 |
dp = va_arg(ap, double*); /* punting on using info enum */ |
442 |
/* |
||
443 |
printf("!%s: got dp = %lu\n", "nrrdAxisInfoSet", |
||
444 |
(unsigned long)(dp)); |
||
445 |
*/ |
||
446 |
✓✓ | 976 |
for (si=0; si<nrrd->spaceDim; si++) { |
447 |
/* nrrd->axis[ai].spaceDirection[si] = dp[si]; */ |
||
448 |
366 |
svec[ai][si] = dp[si]; |
|
449 |
} |
||
450 |
✓✓ | 1464 |
for (si=nrrd->spaceDim; si<NRRD_SPACE_DIM_MAX; si++) { |
451 |
/* nrrd->axis[ai].spaceDirection[si] = AIR_NAN; */ |
||
452 |
610 |
svec[ai][si] = dp[si]; |
|
453 |
} |
||
454 |
break; |
||
455 |
case nrrdAxisInfoCenter: |
||
456 |
case nrrdAxisInfoKind: |
||
457 |
✓✗ | 462 |
info.I[ai] = va_arg(ap, int); |
458 |
/* |
||
459 |
printf("!%s: got int[%d] = %d\n", |
||
460 |
"nrrdAxisInfoSet", d, info.I[ai]); |
||
461 |
*/ |
||
462 |
154 |
break; |
|
463 |
case nrrdAxisInfoSpacing: |
||
464 |
case nrrdAxisInfoThickness: |
||
465 |
case nrrdAxisInfoMin: |
||
466 |
case nrrdAxisInfoMax: |
||
467 |
info.D[ai] = va_arg(ap, double); |
||
468 |
/* |
||
469 |
printf("!%s: got double[%d] = %g\n", |
||
470 |
"nrrdAxisInfoSet", d, info.D[ai]); |
||
471 |
*/ |
||
472 |
break; |
||
473 |
case nrrdAxisInfoLabel: |
||
474 |
/* we DO NOT do the airStrdup() here because this pointer value is |
||
475 |
just going to be handed to nrrdAxisInfoSet_nva(), which WILL do the |
||
476 |
airStrdup(); we're not violating the rules for axis labels */ |
||
477 |
✓✗ | 9 |
info.CP[ai] = va_arg(ap, char *); |
478 |
/* |
||
479 |
printf("!%s: got char*[%d] = |%s|\n", |
||
480 |
"nrrdAxisInfoSet", d, info.CP[ai]); |
||
481 |
*/ |
||
482 |
3 |
break; |
|
483 |
case nrrdAxisInfoUnits: |
||
484 |
/* see not above */ |
||
485 |
info.CP[ai] = va_arg(ap, char *); |
||
486 |
break; |
||
487 |
} |
||
488 |
} |
||
489 |
87 |
va_end(ap); |
|
490 |
|||
491 |
✓✓ | 87 |
if (nrrdAxisInfoSpaceDirection != axInfo) { |
492 |
/* now set the quantities which we've gotten from the var args */ |
||
493 |
49 |
nrrdAxisInfoSet_nva(nrrd, axInfo, info.P); |
|
494 |
49 |
} else { |
|
495 |
38 |
nrrdAxisInfoSet_nva(nrrd, axInfo, svec); |
|
496 |
} |
||
497 |
|||
498 |
87 |
return; |
|
499 |
87 |
} |
|
500 |
|||
501 |
/* |
||
502 |
******** nrrdAxisInfoGet_nva() |
||
503 |
** |
||
504 |
** get any of the axis fields into an array |
||
505 |
** |
||
506 |
** Note that getting axes labels involves implicitly allocating space |
||
507 |
** for them, due to the action of airStrdup(). The user is |
||
508 |
** responsible for free()ing these strings when done with them. |
||
509 |
** |
||
510 |
** type to pass for third argument: |
||
511 |
** nrrdAxisInfoSize: size_t* |
||
512 |
** nrrdAxisInfoSpacing: double* |
||
513 |
** nrrdAxisInfoThickness: double* |
||
514 |
** nrrdAxisInfoMin: double* |
||
515 |
** nrrdAxisInfoMax: double* |
||
516 |
** nrrdAxisInfoSpaceDirection: double (*var)[NRRD_SPACE_DIM_MAX] |
||
517 |
** nrrdAxisInfoCenter: int* |
||
518 |
** nrrdAxisInfoKind: int* |
||
519 |
** nrrdAxisInfoLabel: char** |
||
520 |
** nrrdAxisInfoUnits: char** |
||
521 |
*/ |
||
522 |
void |
||
523 |
nrrdAxisInfoGet_nva(const Nrrd *nrrd, int axInfo, void *_info) { |
||
524 |
_nrrdAxisInfoGetPtrs info; |
||
525 |
unsigned int ai, si; |
||
526 |
|||
527 |
48924 |
if (!( nrrd |
|
528 |
✓✗✓✗ |
73386 |
&& AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX) |
529 |
✗✓ | 24462 |
&& AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) )) { |
530 |
return; |
||
531 |
} |
||
532 |
|||
533 |
24462 |
info.P = _info; |
|
534 |
✓✓ | 196568 |
for (ai=0; ai<nrrd->dim; ai++) { |
535 |
✓✓✓✓ ✓✗✓✓ ✗✗✓ |
147644 |
switch (axInfo) { |
536 |
case nrrdAxisInfoSize: |
||
537 |
13445 |
info.ST[ai] = nrrd->axis[ai].size; |
|
538 |
13445 |
break; |
|
539 |
case nrrdAxisInfoSpacing: |
||
540 |
10053 |
info.D[ai] = nrrd->axis[ai].spacing; |
|
541 |
10053 |
break; |
|
542 |
case nrrdAxisInfoThickness: |
||
543 |
10053 |
info.D[ai] = nrrd->axis[ai].thickness; |
|
544 |
10053 |
break; |
|
545 |
case nrrdAxisInfoMin: |
||
546 |
10059 |
info.D[ai] = nrrd->axis[ai].min; |
|
547 |
10059 |
break; |
|
548 |
case nrrdAxisInfoMax: |
||
549 |
10059 |
info.D[ai] = nrrd->axis[ai].max; |
|
550 |
10059 |
break; |
|
551 |
case nrrdAxisInfoSpaceDirection: |
||
552 |
for (si=0; si<nrrd->spaceDim; si++) { |
||
553 |
info.V[ai][si] = nrrd->axis[ai].spaceDirection[si]; |
||
554 |
} |
||
555 |
for (si=nrrd->spaceDim; si<NRRD_SPACE_DIM_MAX; si++) { |
||
556 |
info.V[ai][si] = AIR_NAN; |
||
557 |
} |
||
558 |
break; |
||
559 |
case nrrdAxisInfoCenter: |
||
560 |
10100 |
info.I[ai] = nrrd->axis[ai].center; |
|
561 |
10100 |
break; |
|
562 |
case nrrdAxisInfoKind: |
||
563 |
10053 |
info.I[ai] = nrrd->axis[ai].kind; |
|
564 |
10053 |
break; |
|
565 |
case nrrdAxisInfoLabel: |
||
566 |
/* note airStrdup()! */ |
||
567 |
info.CP[ai] = airStrdup(nrrd->axis[ai].label); |
||
568 |
break; |
||
569 |
case nrrdAxisInfoUnits: |
||
570 |
/* note airStrdup()! */ |
||
571 |
info.CP[ai] = airStrdup(nrrd->axis[ai].units); |
||
572 |
break; |
||
573 |
} |
||
574 |
} |
||
575 |
✗✓ | 24462 |
if (nrrdAxisInfoSpaceDirection == axInfo) { |
576 |
for (ai=nrrd->dim; ai<NRRD_DIM_MAX; ai++) { |
||
577 |
for (si=0; si<NRRD_SPACE_DIM_MAX; si++) { |
||
578 |
info.V[ai][si] = AIR_NAN; |
||
579 |
} |
||
580 |
} |
||
581 |
} |
||
582 |
24462 |
return; |
|
583 |
24462 |
} |
|
584 |
|||
585 |
/* |
||
586 |
** types to pass, one for each dimension: |
||
587 |
** nrrdAxisInfoSize: size_t* |
||
588 |
** nrrdAxisInfoSpacing: double* |
||
589 |
** nrrdAxisInfoThickness: double* |
||
590 |
** nrrdAxisInfoMin: double* |
||
591 |
** nrrdAxisInfoMax: double* |
||
592 |
** nrrdAxisInfoSpaceDirection: double* |
||
593 |
** nrrdAxisInfoCenter: int* |
||
594 |
** nrrdAxisInfoKind: int* |
||
595 |
** nrrdAxisInfoLabel: char** |
||
596 |
** nrrdAxisInfoUnits: char** |
||
597 |
*/ |
||
598 |
void |
||
599 |
nrrdAxisInfoGet_va(const Nrrd *nrrd, int axInfo, ...) { |
||
600 |
void *buffer[NRRD_DIM_MAX], *ptr; |
||
601 |
_nrrdAxisInfoGetPtrs info; |
||
602 |
unsigned int ai, si; |
||
603 |
va_list ap; |
||
604 |
double svec[NRRD_DIM_MAX][NRRD_SPACE_DIM_MAX]; |
||
605 |
|||
606 |
if (!( nrrd |
||
607 |
&& AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX) |
||
608 |
&& AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) )) { |
||
609 |
return; |
||
610 |
} |
||
611 |
|||
612 |
if (nrrdAxisInfoSpaceDirection != axInfo) { |
||
613 |
info.P = buffer; |
||
614 |
nrrdAxisInfoGet_nva(nrrd, axInfo, info.P); |
||
615 |
} else { |
||
616 |
nrrdAxisInfoGet_nva(nrrd, axInfo, svec); |
||
617 |
} |
||
618 |
|||
619 |
va_start(ap, axInfo); |
||
620 |
for (ai=0; ai<nrrd->dim; ai++) { |
||
621 |
ptr = va_arg(ap, void*); |
||
622 |
/* |
||
623 |
printf("!%s(%d): ptr = %lu\n", |
||
624 |
"nrrdAxisInfoGet", d, (unsigned long)ptr); |
||
625 |
*/ |
||
626 |
switch (axInfo) { |
||
627 |
case nrrdAxisInfoSize: |
||
628 |
*((size_t*)ptr) = info.ST[ai]; |
||
629 |
break; |
||
630 |
case nrrdAxisInfoSpacing: |
||
631 |
case nrrdAxisInfoThickness: |
||
632 |
case nrrdAxisInfoMin: |
||
633 |
case nrrdAxisInfoMax: |
||
634 |
*((double*)ptr) = info.D[ai]; |
||
635 |
/* printf("!%s: got double[%d] = %lg\n", "nrrdAxisInfoGet", d, |
||
636 |
*((double*)ptr)); */ |
||
637 |
break; |
||
638 |
case nrrdAxisInfoSpaceDirection: |
||
639 |
for (si=0; si<nrrd->spaceDim; si++) { |
||
640 |
((double*)ptr)[si] = svec[ai][si]; |
||
641 |
} |
||
642 |
for (si=nrrd->spaceDim; si<NRRD_SPACE_DIM_MAX; si++) { |
||
643 |
((double*)ptr)[si] = AIR_NAN; |
||
644 |
} |
||
645 |
break; |
||
646 |
case nrrdAxisInfoCenter: |
||
647 |
case nrrdAxisInfoKind: |
||
648 |
*((int*)ptr) = info.I[ai]; |
||
649 |
/* printf("!%s: got int[%d] = %d\n", |
||
650 |
"nrrdAxisInfoGet", d, *((int*)ptr)); */ |
||
651 |
break; |
||
652 |
case nrrdAxisInfoLabel: |
||
653 |
case nrrdAxisInfoUnits: |
||
654 |
/* we DO NOT do the airStrdup() here because this pointer value just |
||
655 |
came from nrrdAxisInfoGet_nva(), which already did the airStrdup() */ |
||
656 |
*((char**)ptr) = info.CP[ai]; |
||
657 |
/* printf("!%s: got char*[%d] = |%s|\n", "nrrdAxisInfoSet", d, |
||
658 |
*((char**)ptr)); */ |
||
659 |
break; |
||
660 |
} |
||
661 |
} |
||
662 |
va_end(ap); |
||
663 |
|||
664 |
return; |
||
665 |
} |
||
666 |
|||
667 |
/* |
||
668 |
** _nrrdCenter() |
||
669 |
** |
||
670 |
** for nrrdCenterCell and nrrdCenterNode, return will be the same |
||
671 |
** as input. Converts nrrdCenterUnknown into nrrdDefaultCenter, |
||
672 |
** and then clamps to (nrrdCenterUnknown+1, nrrdCenterLast-1). |
||
673 |
** |
||
674 |
** Thus, this ALWAYS returns nrrdCenterNode or nrrdCenterCell |
||
675 |
** (as long as those are the only two centering schemes). |
||
676 |
*/ |
||
677 |
int |
||
678 |
_nrrdCenter(int center) { |
||
679 |
|||
680 |
339 |
center = (nrrdCenterUnknown == center |
|
681 |
113 |
? nrrdDefaultCenter |
|
682 |
: center); |
||
683 |
✓✗ | 339 |
center = AIR_CLAMP(nrrdCenterUnknown+1, center, nrrdCenterLast-1); |
684 |
113 |
return center; |
|
685 |
} |
||
686 |
|||
687 |
int |
||
688 |
_nrrdCenter2(int center, int defCenter) { |
||
689 |
|||
690 |
center = (nrrdCenterUnknown == center |
||
691 |
? defCenter |
||
692 |
: center); |
||
693 |
center = AIR_CLAMP(nrrdCenterUnknown+1, center, nrrdCenterLast-1); |
||
694 |
return center; |
||
695 |
} |
||
696 |
|||
697 |
|||
698 |
/* |
||
699 |
******** nrrdAxisInfoPos() |
||
700 |
** |
||
701 |
** given a nrrd, an axis, and a (floating point) index space position, |
||
702 |
** return the position implied the axis's min, max, and center |
||
703 |
** Does the opposite of nrrdAxisIdx(). |
||
704 |
** |
||
705 |
** does not use biff |
||
706 |
*/ |
||
707 |
double |
||
708 |
nrrdAxisInfoPos(const Nrrd *nrrd, unsigned int ax, double idx) { |
||
709 |
int center; |
||
710 |
size_t size; |
||
711 |
double min, max; |
||
712 |
|||
713 |
✓✗✗✓ |
3 |
if (!( nrrd && ax <= nrrd->dim-1 )) { |
714 |
return AIR_NAN; |
||
715 |
} |
||
716 |
1 |
center = _nrrdCenter(nrrd->axis[ax].center); |
|
717 |
1 |
min = nrrd->axis[ax].min; |
|
718 |
1 |
max = nrrd->axis[ax].max; |
|
719 |
1 |
size = nrrd->axis[ax].size; |
|
720 |
|||
721 |
✓✗ | 3 |
return NRRD_POS(center, min, max, size, idx); |
722 |
1 |
} |
|
723 |
|||
724 |
/* |
||
725 |
******** nrrdAxisInfoIdx() |
||
726 |
** |
||
727 |
** given a nrrd, an axis, and a (floating point) world space position, |
||
728 |
** return the index implied the axis's min, max, and center. |
||
729 |
** Does the opposite of nrrdAxisPos(). |
||
730 |
** |
||
731 |
** does not use biff |
||
732 |
*/ |
||
733 |
double |
||
734 |
nrrdAxisInfoIdx(const Nrrd *nrrd, unsigned int ax, double pos) { |
||
735 |
int center; |
||
736 |
size_t size; |
||
737 |
double min, max; |
||
738 |
|||
739 |
if (!( nrrd && ax <= nrrd->dim-1 )) { |
||
740 |
return AIR_NAN; |
||
741 |
} |
||
742 |
center = _nrrdCenter(nrrd->axis[ax].center); |
||
743 |
min = nrrd->axis[ax].min; |
||
744 |
max = nrrd->axis[ax].max; |
||
745 |
size = nrrd->axis[ax].size; |
||
746 |
|||
747 |
return NRRD_IDX(center, min, max, size, pos); |
||
748 |
} |
||
749 |
|||
750 |
/* |
||
751 |
******** nrrdAxisInfoPosRange() |
||
752 |
** |
||
753 |
** given a nrrd, an axis, and two (floating point) index space positions, |
||
754 |
** return the range of positions implied the axis's min, max, and center |
||
755 |
** The opposite of nrrdAxisIdxRange() |
||
756 |
*/ |
||
757 |
void |
||
758 |
nrrdAxisInfoPosRange(double *loP, double *hiP, |
||
759 |
const Nrrd *nrrd, unsigned int ax, |
||
760 |
double loIdx, double hiIdx) { |
||
761 |
int center, flip = 0; |
||
762 |
size_t size; |
||
763 |
double min, max, tmp; |
||
764 |
|||
765 |
✓✗✗✓ |
336 |
if (!( loP && hiP && nrrd && ax <= nrrd->dim-1 )) { |
766 |
if (loP) *loP = AIR_NAN; |
||
767 |
if (hiP) *hiP = AIR_NAN; |
||
768 |
return; |
||
769 |
} |
||
770 |
112 |
center = _nrrdCenter(nrrd->axis[ax].center); |
|
771 |
112 |
min = nrrd->axis[ax].min; |
|
772 |
112 |
max = nrrd->axis[ax].max; |
|
773 |
112 |
size = nrrd->axis[ax].size; |
|
774 |
|||
775 |
✗✓ | 112 |
if (loIdx > hiIdx) { |
776 |
flip = 1; |
||
777 |
tmp = loIdx; loIdx = hiIdx; hiIdx = tmp; |
||
778 |
} |
||
779 |
✓✗✓✗ |
224 |
if (nrrdCenterCell == center) { |
780 |
224 |
*loP = AIR_AFFINE(0, loIdx, size, min, max); |
|
781 |
112 |
*hiP = AIR_AFFINE(0, hiIdx+1, size, min, max); |
|
782 |
112 |
} else { |
|
783 |
*loP = AIR_AFFINE(0, loIdx, size-1, min, max); |
||
784 |
*hiP = AIR_AFFINE(0, hiIdx, size-1, min, max); |
||
785 |
} |
||
786 |
✗✓ | 112 |
if (flip) { |
787 |
tmp = *loP; *loP = *hiP; *hiP = tmp; |
||
788 |
} |
||
789 |
|||
790 |
112 |
return; |
|
791 |
112 |
} |
|
792 |
|||
793 |
/* |
||
794 |
******** nrrdAxisInfoIdxRange() |
||
795 |
** |
||
796 |
** given a nrrd, an axis, and two (floating point) world space positions, |
||
797 |
** return the range of index space implied the axis's min, max, and center |
||
798 |
** The opposite of nrrdAxisPosRange(). |
||
799 |
** |
||
800 |
** Actually- there are situations where sending an interval through |
||
801 |
** nrrdAxisIdxRange -> nrrdAxisPosRange -> nrrdAxisIdxRange |
||
802 |
** such as in cell centering, when the range of positions given does |
||
803 |
** not even span one sample. Such as: |
||
804 |
** axis->size = 4, axis->min = -4, axis->max = 4, loPos = 0, hiPos = 1 |
||
805 |
** --> nrrdAxisIdxRange == (2, 1.5) --> nrrdAxisPosRange == (2, -1) |
||
806 |
** The basic problem is that because of the 0.5 offset inherent in |
||
807 |
** cell centering, there are situations where (in terms of the arguments |
||
808 |
** to nrrdAxisIdxRange()) loPos < hiPos, but *loP > *hiP. |
||
809 |
*/ |
||
810 |
void |
||
811 |
nrrdAxisInfoIdxRange(double *loP, double *hiP, |
||
812 |
const Nrrd *nrrd, unsigned int ax, |
||
813 |
double loPos, double hiPos) { |
||
814 |
int center, flip = 0; |
||
815 |
size_t size; |
||
816 |
double min, max, tmp; |
||
817 |
|||
818 |
if (!( loP && hiP && nrrd && ax <= nrrd->dim-1 )) { |
||
819 |
*loP = *hiP = AIR_NAN; |
||
820 |
return; |
||
821 |
} |
||
822 |
center = _nrrdCenter(nrrd->axis[ax].center); |
||
823 |
min = nrrd->axis[ax].min; |
||
824 |
max = nrrd->axis[ax].max; |
||
825 |
size = nrrd->axis[ax].size; |
||
826 |
|||
827 |
if (loPos > hiPos) { |
||
828 |
flip = 1; |
||
829 |
tmp = loPos; loPos = hiPos; hiPos = tmp; |
||
830 |
} |
||
831 |
if (nrrdCenterCell == center) { |
||
832 |
if (min < max) { |
||
833 |
*loP = AIR_AFFINE(min, loPos, max, 0, size); |
||
834 |
*hiP = AIR_AFFINE(min, hiPos, max, -1, size-1); |
||
835 |
} else { |
||
836 |
*loP = AIR_AFFINE(min, loPos, max, -1, size-1); |
||
837 |
*hiP = AIR_AFFINE(min, hiPos, max, 0, size); |
||
838 |
} |
||
839 |
} else { |
||
840 |
*loP = AIR_AFFINE(min, loPos, max, 0, size-1); |
||
841 |
*hiP = AIR_AFFINE(min, hiPos, max, 0, size-1); |
||
842 |
} |
||
843 |
if (flip) { |
||
844 |
tmp = *loP; *loP = *hiP; *hiP = tmp; |
||
845 |
} |
||
846 |
|||
847 |
return; |
||
848 |
} |
||
849 |
|||
850 |
void |
||
851 |
nrrdAxisInfoSpacingSet(Nrrd *nrrd, unsigned int ax) { |
||
852 |
int sign; |
||
853 |
double min, max, tmp; |
||
854 |
|||
855 |
if (!( nrrd && ax <= nrrd->dim-1 )) { |
||
856 |
return; |
||
857 |
} |
||
858 |
|||
859 |
min = nrrd->axis[ax].min; |
||
860 |
max = nrrd->axis[ax].max; |
||
861 |
if (!( AIR_EXISTS(min) && AIR_EXISTS(max) )) { |
||
862 |
/* there's no actual basis on which to set the spacing information, |
||
863 |
but we have to set it something, so here goes .. */ |
||
864 |
nrrd->axis[ax].spacing = nrrdDefaultSpacing; |
||
865 |
return; |
||
866 |
} |
||
867 |
|||
868 |
if (min > max) { |
||
869 |
tmp = min; min = max; max = tmp; |
||
870 |
sign = -1; |
||
871 |
} else { |
||
872 |
sign = 1; |
||
873 |
} |
||
874 |
|||
875 |
/* the skinny */ |
||
876 |
nrrd->axis[ax].spacing = NRRD_SPACING(_nrrdCenter(nrrd->axis[ax].center), |
||
877 |
min, max, nrrd->axis[ax].size); |
||
878 |
nrrd->axis[ax].spacing *= sign; |
||
879 |
|||
880 |
return; |
||
881 |
} |
||
882 |
|||
883 |
void |
||
884 |
nrrdAxisInfoMinMaxSet(Nrrd *nrrd, unsigned int ax, int defCenter) { |
||
885 |
int center; |
||
886 |
double spacing; |
||
887 |
|||
888 |
if (!( nrrd && ax <= nrrd->dim-1 )) { |
||
889 |
return; |
||
890 |
} |
||
891 |
|||
892 |
center = _nrrdCenter2(nrrd->axis[ax].center, defCenter); |
||
893 |
spacing = nrrd->axis[ax].spacing; |
||
894 |
if (!AIR_EXISTS(spacing)) |
||
895 |
spacing = nrrdDefaultSpacing; |
||
896 |
if (nrrdCenterCell == center) { |
||
897 |
nrrd->axis[ax].min = 0; |
||
898 |
nrrd->axis[ax].max = spacing*AIR_CAST(double, nrrd->axis[ax].size); |
||
899 |
} else { |
||
900 |
nrrd->axis[ax].min = 0; |
||
901 |
nrrd->axis[ax].max = spacing*AIR_CAST(double, nrrd->axis[ax].size - 1); |
||
902 |
} |
||
903 |
|||
904 |
return; |
||
905 |
} |
||
906 |
/* ---- BEGIN non-NrrdIO */ |
||
907 |
|||
908 |
/* |
||
909 |
** not using the value comparators in accessors.c because of their |
||
910 |
** slightly strange behavior WRT infinity (+inf < -42). This code |
||
911 |
** may eventually warrant wider availability, for now its here but |
||
912 |
** accessible to nrrd files via privateNrrd.h |
||
913 |
*/ |
||
914 |
int |
||
915 |
_nrrdDblcmp(double aa, double bb) { |
||
916 |
int nna, nnb, ret; |
||
917 |
|||
918 |
✓✓ | 3884 |
nna = AIR_EXISTS(aa) || !airIsNaN(aa); |
919 |
✓✓ | 2904 |
nnb = AIR_EXISTS(bb) || !airIsNaN(bb); |
920 |
✓✓ | 980 |
if (nna && nnb) { |
921 |
/* both either exist or are an infinity */ |
||
922 |
✓✗ | 108 |
ret = (aa < bb |
923 |
? -1 |
||
924 |
36 |
: (aa > bb |
|
925 |
? 1 |
||
926 |
: 0)); |
||
927 |
36 |
} else { |
|
928 |
/* one or the other is NaN */ |
||
929 |
✓✗ | 2832 |
ret = (nna < nnb |
930 |
? -1 |
||
931 |
944 |
: (nna > nnb |
|
932 |
? 1 |
||
933 |
: 0)); |
||
934 |
} |
||
935 |
980 |
return ret; |
|
936 |
} |
||
937 |
|||
938 |
/* |
||
939 |
******** nrrdAxisInfoCompare |
||
940 |
** |
||
941 |
** compares all fields in the NrrdAxisInfoCompare |
||
942 |
** |
||
943 |
** See comment about logic of return value above nrrdCompare() |
||
944 |
** |
||
945 |
** NOTE: the structure of this code is very similar to that of |
||
946 |
** nrrdCompare, and any improvements here should be reflected there |
||
947 |
*/ |
||
948 |
int |
||
949 |
nrrdAxisInfoCompare(const NrrdAxisInfo *axisA, const NrrdAxisInfo *axisB, |
||
950 |
int *differ, char explain[AIR_STRLEN_LARGE]) { |
||
951 |
static const char me[]="nrrdAxisInfoCompare"; |
||
952 |
unsigned int saxi; |
||
953 |
|||
954 |
✗✓ | 40 |
if (!(axisA && axisB && differ)) { |
955 |
biffAddf(NRRD, "%s: got NULL pointer (%p, %p, or %p)", me, |
||
956 |
AIR_CVOIDP(axisA), AIR_CVOIDP(axisB), AIR_VOIDP(differ)); |
||
957 |
return 1; |
||
958 |
} |
||
959 |
|||
960 |
✓✗ | 20 |
if (explain) { |
961 |
20 |
strcpy(explain, ""); |
|
962 |
20 |
} |
|
963 |
✗✓ | 20 |
if (axisA->size != axisB->size) { |
964 |
char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL]; |
||
965 |
*differ = axisA->size < axisB->size ? -1 : 1; |
||
966 |
if (explain) { |
||
967 |
sprintf(explain, "axisA->size=%s %s axisB->size=%s", |
||
968 |
airSprintSize_t(stmp1, axisA->size), |
||
969 |
*differ < 0 ? "<" : ">", |
||
970 |
airSprintSize_t(stmp2, axisB->size)); |
||
971 |
} |
||
972 |
return 0; |
||
973 |
} |
||
974 |
|||
975 |
#define DOUBLE_COMPARE(VAL, STR) \ |
||
976 |
*differ = _nrrdDblcmp(axisA->VAL, axisB->VAL); \ |
||
977 |
if (*differ) { \ |
||
978 |
if (explain) { \ |
||
979 |
sprintf(explain, "axisA->%s %.17g %s axisB->%s %.17g", \ |
||
980 |
STR, axisA->VAL, *differ < 0 ? "<" : ">", \ |
||
981 |
STR, axisB->VAL); \ |
||
982 |
} \ |
||
983 |
return 0; \ |
||
984 |
} |
||
985 |
|||
986 |
✗✓✗✗ |
20 |
DOUBLE_COMPARE(spacing, "spacing"); |
987 |
✗✓✗✗ |
20 |
DOUBLE_COMPARE(thickness, "thickness"); |
988 |
✗✓✗✗ |
20 |
DOUBLE_COMPARE(min, "min"); |
989 |
✗✓✗✗ |
20 |
DOUBLE_COMPARE(max, "max"); |
990 |
✓✓ | 360 |
for (saxi=0; saxi<NRRD_SPACE_DIM_MAX; saxi++) { |
991 |
160 |
char stmp[AIR_STRLEN_SMALL]; |
|
992 |
160 |
sprintf(stmp, "spaceDirection[%u]", saxi); |
|
993 |
✗✓✗✗ |
160 |
DOUBLE_COMPARE(spaceDirection[saxi], stmp); |
994 |
✓✗ | 320 |
} |
995 |
#undef DOUBLE_COMPARE |
||
996 |
|||
997 |
✗✓ | 20 |
if (axisA->center != axisB->center) { |
998 |
*differ = axisA->center < axisB->center ? -1 : 1; |
||
999 |
if (explain) { |
||
1000 |
sprintf(explain, "axisA->center %s %s axisB->center %s", |
||
1001 |
airEnumStr(nrrdCenter, axisA->center), |
||
1002 |
*differ < 0 ? "<" : ">", |
||
1003 |
airEnumStr(nrrdCenter, axisB->center)); |
||
1004 |
} |
||
1005 |
return 0; |
||
1006 |
} |
||
1007 |
✗✓ | 20 |
if (axisA->kind != axisB->kind) { |
1008 |
*differ = axisA->kind < axisB->kind ? -1 : 1; |
||
1009 |
if (explain) { |
||
1010 |
sprintf(explain, "axisA->kind %s %s axisB->kind %s", |
||
1011 |
airEnumStr(nrrdKind, axisA->kind), |
||
1012 |
*differ < 0 ? "<" : ">", |
||
1013 |
airEnumStr(nrrdKind, axisB->kind)); |
||
1014 |
} |
||
1015 |
return 0; |
||
1016 |
} |
||
1017 |
20 |
*differ = airStrcmp(axisA->label, axisB->label); |
|
1018 |
✗✓ | 20 |
if (*differ) { |
1019 |
if (explain) { |
||
1020 |
/* can't safely print whole labels because of fixed-size of explain */ |
||
1021 |
sprintf(explain, "axisA->label %s axisB->label", |
||
1022 |
*differ < 0 ? "<" : ">"); |
||
1023 |
if (strlen(explain) + airStrlen(axisA->label) |
||
1024 |
+ airStrlen(axisB->label) |
||
1025 |
+ 2*strlen(" \"\" ") + 1 < AIR_STRLEN_LARGE) { |
||
1026 |
/* ok, we can print them */ |
||
1027 |
sprintf(explain, "axisA->label \"%s\" %s axisB->label \"%s\"", |
||
1028 |
axisA->label ? axisA->label : "", |
||
1029 |
*differ < 0 ? "<" : ">", |
||
1030 |
axisB->label ? axisB->label : ""); |
||
1031 |
} |
||
1032 |
} |
||
1033 |
return 0; |
||
1034 |
} |
||
1035 |
20 |
*differ = airStrcmp(axisA->units, axisB->units); |
|
1036 |
✗✓ | 20 |
if (*differ) { |
1037 |
if (explain) { |
||
1038 |
/* can't print whole string because of fixed-size of explain */ |
||
1039 |
sprintf(explain, "axisA->units %s axisB->units", |
||
1040 |
*differ < 0 ? "<" : ">"); |
||
1041 |
} |
||
1042 |
return 0; |
||
1043 |
} |
||
1044 |
|||
1045 |
20 |
return 0; |
|
1046 |
20 |
} |
|
1047 |
/* ---- END non-NrrdIO */ |
||
1048 |
|||
1049 |
/* |
||
1050 |
******** nrrdDomainAxesGet |
||
1051 |
** |
||
1052 |
** Based on the per-axis "kind" field, learns which are the domain |
||
1053 |
** (resample-able) axes of an image, in other words, the axes which |
||
1054 |
** correspond to independent variables. The return value is the |
||
1055 |
** number of domain axes, and that many values are set in the given |
||
1056 |
** axisIdx[] array |
||
1057 |
** |
||
1058 |
** NOTE: this takes a wild guess that an unset (nrrdKindUnknown) kind |
||
1059 |
** is a domain axis. |
||
1060 |
*/ |
||
1061 |
unsigned int |
||
1062 |
nrrdDomainAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX]) { |
||
1063 |
unsigned int domAxi, axi; |
||
1064 |
|||
1065 |
if (!( nrrd && axisIdx )) { |
||
1066 |
return 0; |
||
1067 |
} |
||
1068 |
domAxi = 0; |
||
1069 |
for (axi=0; axi<nrrd->dim; axi++) { |
||
1070 |
if (nrrdKindUnknown == nrrd->axis[axi].kind |
||
1071 |
|| nrrdKindIsDomain(nrrd->axis[axi].kind)) { |
||
1072 |
axisIdx[domAxi++] = axi; |
||
1073 |
} |
||
1074 |
} |
||
1075 |
return domAxi; |
||
1076 |
} |
||
1077 |
|||
1078 |
int |
||
1079 |
_nrrdSpaceVecExists(const Nrrd *nrrd, unsigned int axi) { |
||
1080 |
unsigned int sai; |
||
1081 |
int ret; |
||
1082 |
|||
1083 |
✓✗✓✗ ✗✓ |
8328 |
if (!( nrrd && axi < nrrd->dim && nrrd->spaceDim )) { |
1084 |
ret = AIR_FALSE; |
||
1085 |
} else { |
||
1086 |
ret = AIR_TRUE; |
||
1087 |
✓✓ | 16656 |
for (sai=0; sai<nrrd->spaceDim; sai++) { |
1088 |
6246 |
ret &= AIR_EXISTS(nrrd->axis[axi].spaceDirection[sai]); |
|
1089 |
} |
||
1090 |
} |
||
1091 |
2082 |
return ret; |
|
1092 |
} |
||
1093 |
|||
1094 |
unsigned int |
||
1095 |
nrrdSpatialAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX]) { |
||
1096 |
unsigned int spcAxi, axi; |
||
1097 |
|||
1098 |
if (!( nrrd && axisIdx && nrrd->spaceDim)) { |
||
1099 |
return 0; |
||
1100 |
} |
||
1101 |
spcAxi = 0; |
||
1102 |
for (axi=0; axi<nrrd->dim; axi++) { |
||
1103 |
if (_nrrdSpaceVecExists(nrrd, axi)) { |
||
1104 |
axisIdx[spcAxi++] = axi; |
||
1105 |
} |
||
1106 |
} |
||
1107 |
return spcAxi; |
||
1108 |
} |
||
1109 |
|||
1110 |
/* |
||
1111 |
******** nrrdRangeAxesGet |
||
1112 |
** |
||
1113 |
** Based on the per-axis "kind" field, learns which are the range |
||
1114 |
** (non-resample-able) axes of an image, in other words, the axes |
||
1115 |
** which correspond to dependent variables. The return value is the |
||
1116 |
** number of range axes; that number of values are set in the given |
||
1117 |
** axisIdx[] array |
||
1118 |
** |
||
1119 |
** Note: this really is as simple as returning the complement of the |
||
1120 |
** axis selected by nrrdDomainAxesGet() |
||
1121 |
*/ |
||
1122 |
unsigned int |
||
1123 |
nrrdRangeAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX]) { |
||
1124 |
unsigned int domNum, domIdx[NRRD_DIM_MAX], rngAxi, axi, ii, isDom; |
||
1125 |
|||
1126 |
if (!( nrrd && axisIdx )) { |
||
1127 |
return 0; |
||
1128 |
} |
||
1129 |
domNum = nrrdDomainAxesGet(nrrd, domIdx); |
||
1130 |
rngAxi = 0; |
||
1131 |
for (axi=0; axi<nrrd->dim; axi++) { |
||
1132 |
isDom = AIR_FALSE; |
||
1133 |
for (ii=0; ii<domNum; ii++) { /* yes, inefficient */ |
||
1134 |
isDom |= axi == domIdx[ii]; |
||
1135 |
} |
||
1136 |
if (!isDom) { |
||
1137 |
axisIdx[rngAxi++] = axi; |
||
1138 |
} |
||
1139 |
} |
||
1140 |
return rngAxi; |
||
1141 |
} |
||
1142 |
|||
1143 |
unsigned int |
||
1144 |
nrrdNonSpatialAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX]) { |
||
1145 |
unsigned int spcNum, spcIdx[NRRD_DIM_MAX], nspAxi, axi, ii, isSpc; |
||
1146 |
|||
1147 |
if (!( nrrd && axisIdx )) { |
||
1148 |
return 0; |
||
1149 |
} |
||
1150 |
/* HEY: copy and paste, should refactor with above */ |
||
1151 |
spcNum = nrrdSpatialAxesGet(nrrd, spcIdx); |
||
1152 |
nspAxi = 0; |
||
1153 |
for (axi=0; axi<nrrd->dim; axi++) { |
||
1154 |
isSpc = AIR_FALSE; |
||
1155 |
for (ii=0; ii<spcNum; ii++) { /* yes, inefficient */ |
||
1156 |
isSpc |= axi == spcIdx[ii]; |
||
1157 |
} |
||
1158 |
if (!isSpc) { |
||
1159 |
axisIdx[nspAxi++] = axi; |
||
1160 |
} |
||
1161 |
} |
||
1162 |
return nspAxi; |
||
1163 |
} |
||
1164 |
|||
1165 |
|||
1166 |
/* |
||
1167 |
******** nrrdSpacingCalculate |
||
1168 |
** |
||
1169 |
** Determine nrrdSpacingStatus, and whatever can be calculated about |
||
1170 |
** spacing for a given axis. Takes a nrrd, an axis, a double pointer |
||
1171 |
** (for returning a scalar), a space vector, and an int pointer for |
||
1172 |
** returning the known length of the space vector. |
||
1173 |
** |
||
1174 |
** The behavior of what has been set by the function is determined by |
||
1175 |
** the return value, which takes values from the nrrdSpacingStatus* |
||
1176 |
** enum, as follows: |
||
1177 |
** |
||
1178 |
** returned status value: what it means, and what it set |
||
1179 |
** --------------------------------------------------------------------------- |
||
1180 |
** nrrdSpacingStatusUnknown Something about the given arguments is |
||
1181 |
** invalid. |
||
1182 |
** *spacing = NaN, |
||
1183 |
** vector = all NaNs |
||
1184 |
** |
||
1185 |
** nrrdSpacingStatusNone There is no spacing info at all: |
||
1186 |
** *spacing = NaN, |
||
1187 |
** vector = all NaNs |
||
1188 |
** |
||
1189 |
** nrrdSpacingStatusScalarNoSpace There is no surrounding space, but the |
||
1190 |
** axis's spacing was known. |
||
1191 |
** *spacing = axis->spacing, |
||
1192 |
** vector = all NaNs |
||
1193 |
** |
||
1194 |
** nrrdSpacingStatusScalarWithSpace There *is* a surrounding space, but the |
||
1195 |
** given axis does not live in that space, |
||
1196 |
** because it has no space direction. Caller |
||
1197 |
** may want to think about what's going on. |
||
1198 |
** *spacing = axis->spacing, |
||
1199 |
** vector = all NaNs |
||
1200 |
** |
||
1201 |
** nrrdSpacingStatusDirection There is a surrounding space, in which |
||
1202 |
** this axis has a direction V: |
||
1203 |
** *spacing = |V| (length of direction), |
||
1204 |
** vector = V/|V| (normalized direction) |
||
1205 |
** NOTE: it is still possible for both |
||
1206 |
** *spacing and vector to be all NaNs!! |
||
1207 |
*/ |
||
1208 |
int |
||
1209 |
nrrdSpacingCalculate(const Nrrd *nrrd, unsigned int ax, |
||
1210 |
double *spacing, double vector[NRRD_SPACE_DIM_MAX]) { |
||
1211 |
int ret; |
||
1212 |
|||
1213 |
✓✗✗✓ |
6246 |
if (!( nrrd && spacing && vector |
1214 |
2082 |
&& ax <= nrrd->dim-1 |
|
1215 |
✓✗ | 4164 |
&& !_nrrdCheck(nrrd, AIR_FALSE, AIR_FALSE) )) { |
1216 |
/* there's a problem with the arguments. Note: the _nrrdCheck() |
||
1217 |
call does not check on non-NULL-ity of nrrd->data */ |
||
1218 |
ret = nrrdSpacingStatusUnknown; |
||
1219 |
if (spacing) { |
||
1220 |
*spacing = AIR_NAN; |
||
1221 |
} |
||
1222 |
if (vector) { |
||
1223 |
nrrdSpaceVecSetNaN(vector); |
||
1224 |
} |
||
1225 |
} else { |
||
1226 |
✗✓✗✓ |
4164 |
if (AIR_EXISTS(nrrd->axis[ax].spacing)) { |
1227 |
✗✗ | 2082 |
if (nrrd->spaceDim > 0) { |
1228 |
ret = nrrdSpacingStatusScalarWithSpace; |
||
1229 |
} else { |
||
1230 |
ret = nrrdSpacingStatusScalarNoSpace; |
||
1231 |
} |
||
1232 |
*spacing = nrrd->axis[ax].spacing; |
||
1233 |
nrrdSpaceVecSetNaN(vector); |
||
1234 |
} else { |
||
1235 |
✓✗✓✗ |
4164 |
if (nrrd->spaceDim > 0 && _nrrdSpaceVecExists(nrrd, ax)) { |
1236 |
ret = nrrdSpacingStatusDirection; |
||
1237 |
4164 |
*spacing = nrrdSpaceVecNorm(nrrd->spaceDim, |
|
1238 |
2082 |
nrrd->axis[ax].spaceDirection); |
|
1239 |
2082 |
nrrdSpaceVecScale(vector, 1.0/(*spacing), |
|
1240 |
nrrd->axis[ax].spaceDirection); |
||
1241 |
2082 |
} else { |
|
1242 |
ret = nrrdSpacingStatusNone; |
||
1243 |
*spacing = AIR_NAN; |
||
1244 |
nrrdSpaceVecSetNaN(vector); |
||
1245 |
} |
||
1246 |
} |
||
1247 |
} |
||
1248 |
2082 |
return ret; |
|
1249 |
} |
||
1250 |
|||
1251 |
int |
||
1252 |
nrrdOrientationReduce(Nrrd *nout, const Nrrd *nin, |
||
1253 |
int setMinsFromOrigin) { |
||
1254 |
static const char me[]="nrrdOrientationReduce"; |
||
1255 |
unsigned int spatialAxisNum, spatialAxisIdx[NRRD_DIM_MAX], saxii; |
||
1256 |
NrrdAxisInfo *axis; |
||
1257 |
|||
1258 |
if (!(nout && nin)) { |
||
1259 |
biffAddf(NRRD, "%s: got NULL pointer", me); |
||
1260 |
return 1; |
||
1261 |
} |
||
1262 |
|||
1263 |
if (nout != nin) { |
||
1264 |
if (nrrdCopy(nout, nin)) { |
||
1265 |
biffAddf(NRRD, "%s: trouble doing initial copying", me); |
||
1266 |
return 1; |
||
1267 |
} |
||
1268 |
} |
||
1269 |
if (!nout->spaceDim) { |
||
1270 |
/* we're done! */ |
||
1271 |
return 0; |
||
1272 |
} |
||
1273 |
spatialAxisNum = nrrdSpatialAxesGet(nout, spatialAxisIdx); |
||
1274 |
for (saxii=0; saxii<spatialAxisNum; saxii++) { |
||
1275 |
axis = nout->axis + spatialAxisIdx[saxii]; |
||
1276 |
axis->spacing = nrrdSpaceVecNorm(nout->spaceDim, |
||
1277 |
axis->spaceDirection); |
||
1278 |
if (setMinsFromOrigin) { |
||
1279 |
axis->min = (saxii < nout->spaceDim |
||
1280 |
? nout->spaceOrigin[saxii] |
||
1281 |
: AIR_NAN); |
||
1282 |
} |
||
1283 |
} |
||
1284 |
nrrdSpaceSet(nout, nrrdSpaceUnknown); |
||
1285 |
|||
1286 |
return 0; |
||
1287 |
} |
||
1288 |
|||
1289 |
/* |
||
1290 |
******** nrrdMetaData |
||
1291 |
** |
||
1292 |
** The brains of "unu dnorm" (for Diderot normalization): put all meta-data |
||
1293 |
** of a nrrd into some simpler canonical form. |
||
1294 |
** |
||
1295 |
** This function probably doesn't belong in this file, but it is kind |
||
1296 |
** the opposite of nrrdOrientationReduce (above), so here it is |
||
1297 |
*/ |
||
1298 |
int |
||
1299 |
nrrdMetaDataNormalize(Nrrd *nout, const Nrrd *nin, |
||
1300 |
int version, |
||
1301 |
int trivialOrient, |
||
1302 |
int permuteComponentAxisFastest, |
||
1303 |
int recenterGrid, |
||
1304 |
double sampleSpacing, |
||
1305 |
int *lostMeasurementFrame) { |
||
1306 |
static const char me[]="nrrdMetaDataNormalize"; |
||
1307 |
size_t size[NRRD_DIM_MAX]; |
||
1308 |
int kindIn, kindOut, haveMM, gotmf; |
||
1309 |
unsigned int kindAxis, axi, si, sj; |
||
1310 |
Nrrd *ntmp; |
||
1311 |
airArray *mop; |
||
1312 |
|||
1313 |
if (!(nout && nin)) { |
||
1314 |
biffAddf(NRRD, "%s: got NULL pointer", me); |
||
1315 |
return 1; |
||
1316 |
} |
||
1317 |
if (airEnumValCheck(nrrdMetaDataCanonicalVersion, version)) { |
||
1318 |
biffAddf(NRRD, "%s: version %d not valid %s", me, |
||
1319 |
version, nrrdMetaDataCanonicalVersion->name); |
||
1320 |
return 1; |
||
1321 |
} |
||
1322 |
if (nrrdMetaDataCanonicalVersionAlpha != version) { |
||
1323 |
biffAddf(NRRD, "%s: sorry, %s %s not implemented (only %s)", me, |
||
1324 |
nrrdMetaDataCanonicalVersion->name, |
||
1325 |
airEnumStr(nrrdMetaDataCanonicalVersion, version), |
||
1326 |
airEnumStr(nrrdMetaDataCanonicalVersion, |
||
1327 |
nrrdMetaDataCanonicalVersionAlpha)); |
||
1328 |
return 1; |
||
1329 |
} |
||
1330 |
|||
1331 |
if (_nrrdCheck(nin, AIR_FALSE /* checkData */, AIR_TRUE /* useBiff */)) { |
||
1332 |
biffAddf(NRRD, "%s: basic check failed", me); |
||
1333 |
return 1; |
||
1334 |
} |
||
1335 |
/* but can't deal with block type */ |
||
1336 |
if (nrrdTypeBlock == nin->type) { |
||
1337 |
biffAddf(NRRD, "%s: can only have scalar types (not %s)", me, |
||
1338 |
airEnumStr(nrrdType, nrrdTypeBlock)); |
||
1339 |
return 1; |
||
1340 |
} |
||
1341 |
|||
1342 |
/* look at all per-axis kinds */ |
||
1343 |
/* see if there's a range kind, verify that there's only one */ |
||
1344 |
/* set haveMM */ |
||
1345 |
haveMM = AIR_TRUE; |
||
1346 |
kindIn = nrrdKindUnknown; |
||
1347 |
kindAxis = 0; /* only means something if kindIn != nrrdKindUnknown */ |
||
1348 |
for (axi=0; axi<nin->dim; axi++) { |
||
1349 |
if (nrrdKindUnknown == nin->axis[axi].kind |
||
1350 |
|| nrrdKindIsDomain(nin->axis[axi].kind)) { |
||
1351 |
haveMM &= AIR_EXISTS(nin->axis[axi].min); |
||
1352 |
haveMM &= AIR_EXISTS(nin->axis[axi].max); |
||
1353 |
} else { |
||
1354 |
if (nrrdKindUnknown != kindIn) { |
||
1355 |
biffAddf(NRRD, "%s: got non-domain kind %s on axis %u, but already " |
||
1356 |
"have kind %s on previous axis %u", me, |
||
1357 |
airEnumStr(nrrdKind, nin->axis[axi].kind), axi, |
||
1358 |
airEnumStr(nrrdKind, kindIn), kindAxis); |
||
1359 |
return 1; |
||
1360 |
} |
||
1361 |
kindIn = nin->axis[axi].kind; |
||
1362 |
kindAxis = axi; |
||
1363 |
} |
||
1364 |
} |
||
1365 |
|||
1366 |
if (nrrdKindUnknown != kindIn && kindAxis) { |
||
1367 |
/* have a non-domain axis, and it isn't the fastest */ |
||
1368 |
if (permuteComponentAxisFastest) { |
||
1369 |
if (nout == nin) { |
||
1370 |
biffAddf(NRRD, "%s: can't permute non-domain axis %u (kind %s) " |
||
1371 |
"to axis 0 with nout == nin", me, |
||
1372 |
kindAxis, airEnumStr(nrrdKind, kindIn)); |
||
1373 |
return 1; |
||
1374 |
} |
||
1375 |
biffAddf(NRRD, "%s: sorry, permuting non-domain axis %u (kind %s) " |
||
1376 |
"to axis 0 not yet implemented", me, |
||
1377 |
kindAxis, airEnumStr(nrrdKind, kindIn)); |
||
1378 |
return 1; |
||
1379 |
} else { |
||
1380 |
/* caller thinks its okay for non-domain axis to be on |
||
1381 |
something other than fastest axis */ |
||
1382 |
if (nrrdMetaDataCanonicalVersionAlpha == version) { |
||
1383 |
biffAddf(NRRD, "%s: (%s) non-domain axis %u (kind %s) " |
||
1384 |
"must be fastest axis", me, |
||
1385 |
airEnumStr(nrrdMetaDataCanonicalVersion, version), |
||
1386 |
kindAxis, airEnumStr(nrrdKind, kindIn)); |
||
1387 |
return 1; |
||
1388 |
} |
||
1389 |
/* maybe with nrrdMetaDataCanonicalVersionAlpha != version |
||
1390 |
it is okay to have non-domain axis on non-fastest axis? */ |
||
1391 |
} |
||
1392 |
} |
||
1393 |
|||
1394 |
/* HEY: would be nice to handle a stub "scalar" axis by deleting it */ |
||
1395 |
|||
1396 |
/* see if the non-domain kind is something we can interpret as a tensor */ |
||
1397 |
if (nrrdKindUnknown != kindIn) { |
||
1398 |
switch (kindIn) { |
||
1399 |
/* ======= THESE are the kinds that we can possibly output ======= */ |
||
1400 |
case nrrdKind2Vector: |
||
1401 |
case nrrdKind3Vector: |
||
1402 |
case nrrdKind4Vector: |
||
1403 |
case nrrdKind2DSymMatrix: |
||
1404 |
case nrrdKind2DMatrix: |
||
1405 |
case nrrdKind3DSymMatrix: |
||
1406 |
case nrrdKind3DMatrix: |
||
1407 |
/* =============================================================== */ |
||
1408 |
kindOut = kindIn; |
||
1409 |
break; |
||
1410 |
/* Some other kinds are mapped to those above */ |
||
1411 |
case nrrdKind3Color: |
||
1412 |
case nrrdKindRGBColor: |
||
1413 |
kindOut = nrrdKind3Vector; |
||
1414 |
break; |
||
1415 |
case nrrdKind4Color: |
||
1416 |
case nrrdKindRGBAColor: |
||
1417 |
kindOut = nrrdKind4Vector; |
||
1418 |
break; |
||
1419 |
default: |
||
1420 |
biffAddf(NRRD, "%s: got non-conforming kind %s on axis %u", me, |
||
1421 |
airEnumStr(nrrdKind, kindIn), kindAxis); |
||
1422 |
return 1; |
||
1423 |
} |
||
1424 |
} else { |
||
1425 |
/* kindIn is nrrdKindUnknown, so its a simple scalar image, |
||
1426 |
and that's what the output will be too; kindOut == nrrdKindUnknown |
||
1427 |
is used in the code below to say "its a scalar image" */ |
||
1428 |
kindOut = nrrdKindUnknown; |
||
1429 |
} |
||
1430 |
|||
1431 |
/* initialize output by copying meta-data from nin to ntmp */ |
||
1432 |
mop = airMopNew(); |
||
1433 |
ntmp = nrrdNew(); |
||
1434 |
airMopAdd(mop, ntmp, (airMopper)nrrdNix, airMopAlways); |
||
1435 |
/* HEY this is doing the work of a shallow copy, which isn't |
||
1436 |
available in the API. You can pass nrrdCopy() a nin with NULL |
||
1437 |
nin->data, which implements a shallow copy, but we can't set |
||
1438 |
nin->data=NULL here because of const correctness */ |
||
1439 |
nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size); |
||
1440 |
if (nrrdWrap_nva(ntmp, NULL, nin->type, nin->dim, size)) { |
||
1441 |
biffAddf(NRRD, "%s: couldn't wrap buffer nrrd around NULL", me); |
||
1442 |
airMopError(mop); return 1; |
||
1443 |
} |
||
1444 |
/* so ntmp->data == NULL */ |
||
1445 |
nrrdAxisInfoCopy(ntmp, nin, NULL, NRRD_AXIS_INFO_SIZE_BIT); |
||
1446 |
if (nrrdBasicInfoCopy(ntmp, nin, NRRD_BASIC_INFO_DATA_BIT)) { |
||
1447 |
biffAddf(NRRD, "%s: trouble copying basic info", me); |
||
1448 |
airMopError(mop); return 1; |
||
1449 |
} |
||
1450 |
|||
1451 |
/* no comments */ |
||
1452 |
nrrdCommentClear(ntmp); |
||
1453 |
|||
1454 |
/* no measurement frame */ |
||
1455 |
gotmf = AIR_FALSE; |
||
1456 |
for (si=0; si<NRRD_SPACE_DIM_MAX; si++) { |
||
1457 |
for (sj=0; sj<NRRD_SPACE_DIM_MAX; sj++) { |
||
1458 |
gotmf |= AIR_EXISTS(ntmp->measurementFrame[si][sj]); |
||
1459 |
} |
||
1460 |
} |
||
1461 |
if (lostMeasurementFrame) { |
||
1462 |
*lostMeasurementFrame = gotmf; |
||
1463 |
} |
||
1464 |
for (si=0; si<NRRD_SPACE_DIM_MAX; si++) { |
||
1465 |
for (sj=0; sj<NRRD_SPACE_DIM_MAX; sj++) { |
||
1466 |
ntmp->measurementFrame[si][sj] = AIR_NAN; |
||
1467 |
} |
||
1468 |
} |
||
1469 |
|||
1470 |
/* no key/value pairs */ |
||
1471 |
nrrdKeyValueClear(ntmp); |
||
1472 |
|||
1473 |
/* no content field */ |
||
1474 |
ntmp->content = airFree(ntmp->content); |
||
1475 |
|||
1476 |
/* normalize domain kinds to "space" */ |
||
1477 |
/* HEY: if Diderot supports time-varying fields, this will have to change */ |
||
1478 |
/* turn off centers (current Diderot semantics don't expose centering) */ |
||
1479 |
/* turn off thickness */ |
||
1480 |
/* turn off labels and units */ |
||
1481 |
for (axi=0; axi<ntmp->dim; axi++) { |
||
1482 |
if (nrrdKindUnknown == kindOut) { |
||
1483 |
ntmp->axis[axi].kind = nrrdKindSpace; |
||
1484 |
} else { |
||
1485 |
ntmp->axis[axi].kind = (kindAxis == axi |
||
1486 |
? kindOut |
||
1487 |
: nrrdKindSpace); |
||
1488 |
} |
||
1489 |
ntmp->axis[axi].center = nrrdCenterUnknown; |
||
1490 |
ntmp->axis[axi].thickness = AIR_NAN; |
||
1491 |
ntmp->axis[axi].label = airFree(ntmp->axis[axi].label); |
||
1492 |
ntmp->axis[axi].units = airFree(ntmp->axis[axi].units); |
||
1493 |
ntmp->axis[axi].min = AIR_NAN; |
||
1494 |
ntmp->axis[axi].max = AIR_NAN; |
||
1495 |
ntmp->axis[axi].spacing = AIR_NAN; |
||
1496 |
} |
||
1497 |
|||
1498 |
/* logic of orientation definition: |
||
1499 |
If space dimension is known: |
||
1500 |
set origin to zero if not already set |
||
1501 |
set space direction to unit vector if not already set |
||
1502 |
Else if have per-axis min and max: |
||
1503 |
set spae origin and directions to communicate same intent |
||
1504 |
as original per-axis min and max and original centering |
||
1505 |
Else |
||
1506 |
set origin to zero and all space directions to units. |
||
1507 |
(It might be nice to use gage's logic for mapping from world to index, |
||
1508 |
but we have to accept a greater variety of kinds and dimensions |
||
1509 |
than gage ever has to process.) |
||
1510 |
The result is that space origin and space directions are set. |
||
1511 |
the "space" field is not used, only "spaceDim" |
||
1512 |
*/ |
||
1513 |
/* no named space */ |
||
1514 |
ntmp->space = nrrdSpaceUnknown; |
||
1515 |
if (ntmp->spaceDim && !trivialOrient) { |
||
1516 |
int saxi = 0; |
||
1517 |
if (!nrrdSpaceVecExists(ntmp->spaceDim, ntmp->spaceOrigin)) { |
||
1518 |
nrrdSpaceVecSetZero(ntmp->spaceOrigin); |
||
1519 |
} |
||
1520 |
for (axi=0; axi<ntmp->dim; axi++) { |
||
1521 |
if (nrrdKindUnknown == kindOut || kindAxis != axi) { |
||
1522 |
/* its a domain axis of output */ |
||
1523 |
if (!nrrdSpaceVecExists(ntmp->spaceDim, |
||
1524 |
ntmp->axis[axi].spaceDirection)) { |
||
1525 |
nrrdSpaceVecSetZero(ntmp->axis[axi].spaceDirection); |
||
1526 |
ntmp->axis[axi].spaceDirection[saxi] = sampleSpacing; |
||
1527 |
} |
||
1528 |
/* else we leave existing space vector as is */ |
||
1529 |
saxi++; |
||
1530 |
} else { |
||
1531 |
/* else its a range (non-domain, component) axis */ |
||
1532 |
nrrdSpaceVecSetNaN(ntmp->axis[axi].spaceDirection); |
||
1533 |
} |
||
1534 |
} |
||
1535 |
} else if (haveMM && !trivialOrient) { |
||
1536 |
int saxi = 0; |
||
1537 |
size_t N; |
||
1538 |
double rng; |
||
1539 |
for (axi=0; axi<ntmp->dim; axi++) { |
||
1540 |
if (nrrdKindUnknown == kindOut || kindAxis != axi) { |
||
1541 |
/* its a domain axis of output */ |
||
1542 |
nrrdSpaceVecSetZero(ntmp->axis[axi].spaceDirection); |
||
1543 |
rng = nin->axis[axi].max - nin->axis[axi].min; |
||
1544 |
if (nrrdCenterNode == nin->axis[axi].center) { |
||
1545 |
ntmp->spaceOrigin[saxi] = nin->axis[axi].min; |
||
1546 |
N = nin->axis[axi].size; |
||
1547 |
ntmp->axis[axi].spaceDirection[saxi] = rng/(N-1); |
||
1548 |
} else { |
||
1549 |
/* unknown centering treated as cell */ |
||
1550 |
N = nin->axis[axi].size; |
||
1551 |
ntmp->spaceOrigin[saxi] = nin->axis[axi].min + (rng/N)/2; |
||
1552 |
ntmp->axis[axi].spaceDirection[saxi] = rng/N; |
||
1553 |
} |
||
1554 |
saxi++; |
||
1555 |
} else { |
||
1556 |
/* else its a range axis */ |
||
1557 |
nrrdSpaceVecSetNaN(ntmp->axis[axi].spaceDirection); |
||
1558 |
} |
||
1559 |
} |
||
1560 |
ntmp->spaceDim = saxi; |
||
1561 |
} else { |
||
1562 |
/* either trivialOrient, or, not spaceDim and not haveMM */ |
||
1563 |
int saxi = 0; |
||
1564 |
nrrdSpaceVecSetZero(ntmp->spaceOrigin); |
||
1565 |
for (axi=0; axi<ntmp->dim; axi++) { |
||
1566 |
if (nrrdKindUnknown == kindOut || kindAxis != axi) { |
||
1567 |
/* its a domain axis of output */ |
||
1568 |
nrrdSpaceVecSetZero(ntmp->axis[axi].spaceDirection); |
||
1569 |
ntmp->axis[axi].spaceDirection[saxi] |
||
1570 |
= (AIR_EXISTS(nin->axis[axi].spacing) |
||
1571 |
? nin->axis[axi].spacing |
||
1572 |
: sampleSpacing); |
||
1573 |
saxi++; |
||
1574 |
} else { |
||
1575 |
/* else its a range axis */ |
||
1576 |
nrrdSpaceVecSetNaN(ntmp->axis[axi].spaceDirection); |
||
1577 |
} |
||
1578 |
} |
||
1579 |
ntmp->spaceDim = saxi; |
||
1580 |
} |
||
1581 |
|||
1582 |
/* space dimension has to match the number of domain axes */ |
||
1583 |
if (ntmp->dim != ntmp->spaceDim + !!kindOut) { |
||
1584 |
biffAddf(NRRD, "%s: output dim %d != spaceDim %d + %d %s%s%s%s", |
||
1585 |
me, ntmp->dim, ntmp->spaceDim, !!kindOut, |
||
1586 |
kindOut ? "for non-scalar (" : "(scalar data)", |
||
1587 |
kindOut ? airEnumStr(nrrdKind, kindOut) : "", |
||
1588 |
kindOut ? ") data" : "", |
||
1589 |
kindOut ? "" : "; a non-domain axis in the input " |
||
1590 |
"may be missing an informative \"kind\", leading to the " |
||
1591 |
"false assumption of a scalar array"); |
||
1592 |
airMopError(mop); return 1; |
||
1593 |
} |
||
1594 |
|||
1595 |
if (recenterGrid) { |
||
1596 |
/* sets field's origin so field is centered on the origin. capiche? */ |
||
1597 |
/* this code was tacked on later than the stuff above, so its |
||
1598 |
logic could probably be moved up there, but it seems cleaner to |
||
1599 |
have it as a separate post-process */ |
||
1600 |
double mean[NRRD_SPACE_DIM_MAX]; |
||
1601 |
nrrdSpaceVecSetZero(mean); |
||
1602 |
for (axi=0; axi<ntmp->dim; axi++) { |
||
1603 |
if (nrrdKindUnknown == kindOut || kindAxis != axi) { |
||
1604 |
nrrdSpaceVecScaleAdd2(mean, 1.0, mean, |
||
1605 |
0.5*(ntmp->axis[axi].size - 1), |
||
1606 |
ntmp->axis[axi].spaceDirection); |
||
1607 |
} |
||
1608 |
} |
||
1609 |
nrrdSpaceVecScaleAdd2(mean, 1.0, mean, |
||
1610 |
1.0, ntmp->spaceOrigin); |
||
1611 |
/* now mean is the center of the field */ |
||
1612 |
nrrdSpaceVecScaleAdd2(ntmp->spaceOrigin, |
||
1613 |
1.0, ntmp->spaceOrigin, |
||
1614 |
-1.0, mean); |
||
1615 |
} |
||
1616 |
|||
1617 |
/* with that all done, now copy from ntmp to nout */ |
||
1618 |
if (nout != nin) { |
||
1619 |
/* have to copy data */ |
||
1620 |
ntmp->data = nin->data; |
||
1621 |
if (nrrdCopy(nout, ntmp)) { |
||
1622 |
biffAddf(NRRD, "%s: problem copying (with data) to output", me); |
||
1623 |
airMopError(mop); return 1; |
||
1624 |
} |
||
1625 |
} else { |
||
1626 |
/* nout == nin; have to copy only meta-data, leave data as is */ |
||
1627 |
void *data = nin->data; |
||
1628 |
/* ntmp->data == NULL, so this is a shallow copy */ |
||
1629 |
if (nrrdCopy(nout, ntmp)) { |
||
1630 |
biffAddf(NRRD, "%s: problem copying meta-data to output", me); |
||
1631 |
airMopError(mop); return 1; |
||
1632 |
} |
||
1633 |
nout->data = data; |
||
1634 |
} |
||
1635 |
|||
1636 |
airMopOkay(mop); |
||
1637 |
return 0; |
||
1638 |
} |
||
1639 |
Generated by: GCOVR (Version 3.3) |