File: | src/nrrd/axis.c |
Location: | line 819, column 17 |
Description: | Dereference of null pointer (loaded from variable 'hiP') |
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 | if (axis) { | |||
34 | axis->size = 0; | |||
35 | axis->spacing = axis->thickness = AIR_NAN(airFloatQNaN.f); | |||
36 | axis->min = axis->max = AIR_NAN(airFloatQNaN.f); | |||
37 | for (dd=0; dd<NRRD_SPACE_DIM_MAX8; dd++) { | |||
38 | axis->spaceDirection[dd] = AIR_NAN(airFloatQNaN.f); | |||
39 | } | |||
40 | axis->center = nrrdCenterUnknown; | |||
41 | axis->kind = nrrdKindUnknown; | |||
42 | axis->label = (char *)airFree(axis->label); | |||
43 | axis->units = (char *)airFree(axis->units); | |||
44 | } | |||
45 | } | |||
46 | ||||
47 | void | |||
48 | _nrrdAxisInfoNewInit(NrrdAxisInfo *axis) { | |||
49 | ||||
50 | if (axis) { | |||
51 | axis->label = NULL((void*)0); | |||
52 | axis->units = NULL((void*)0); | |||
53 | _nrrdAxisInfoInit(axis); | |||
54 | } | |||
55 | } | |||
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 | return (nrrdKindDomain == kind | |||
70 | || nrrdKindSpace == kind | |||
71 | || 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 | if (!( AIR_IN_OP(nrrdKindUnknown, kind, nrrdKindLast)((nrrdKindUnknown) < (kind) && (kind) < (nrrdKindLast )) )) { | |||
87 | /* they gave us invalid or unknown kind */ | |||
88 | return 0; | |||
89 | } | |||
90 | ||||
91 | 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 | break; | |||
102 | case nrrdKindStub: | |||
103 | case nrrdKindScalar: | |||
104 | ret = 1; | |||
105 | 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 | break; | |||
143 | case nrrdKind3DMaskedSymMatrix: | |||
144 | ret = 7; | |||
145 | break; | |||
146 | case nrrdKind3DMatrix: | |||
147 | ret = 9; | |||
148 | break; | |||
149 | case nrrdKind3DMaskedMatrix: | |||
150 | ret = 10; | |||
151 | break; | |||
152 | default: | |||
153 | fprintf(stderr__stderrp, "%s: PANIC: nrrdKind %d not implemented!\n", me, kind); | |||
154 | ret = UINT_MAX(2147483647 *2U +1U); | |||
155 | } | |||
156 | ||||
157 | return ret; | |||
158 | } | |||
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 | 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 | if (nrrdKindIsDomain(kindIn) | |||
177 | || (0 == nrrdKindSize(kindIn) && !resampling)) { | |||
178 | kindOut = kindIn; | |||
179 | } else { | |||
180 | kindOut = nrrdKindUnknown; | |||
181 | } | |||
182 | } | |||
183 | 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 | if (!(NRRD_AXIS_INFO_SIZE_BIT(1<< 1) & bitflag)) { | |||
197 | dest->size = src->size; | |||
198 | } | |||
199 | if (!(NRRD_AXIS_INFO_SPACING_BIT(1<< 2) & bitflag)) { | |||
200 | dest->spacing = src->spacing; | |||
201 | } | |||
202 | if (!(NRRD_AXIS_INFO_THICKNESS_BIT(1<< 3) & bitflag)) { | |||
203 | dest->thickness = src->thickness; | |||
204 | } | |||
205 | if (!(NRRD_AXIS_INFO_MIN_BIT(1<< 4) & bitflag)) { | |||
206 | dest->min = src->min; | |||
207 | } | |||
208 | if (!(NRRD_AXIS_INFO_MAX_BIT(1<< 5) & bitflag)) { | |||
209 | dest->max = src->max; | |||
210 | } | |||
211 | if (!(NRRD_AXIS_INFO_SPACEDIRECTION_BIT(1<< 6) & bitflag)) { | |||
212 | for (ii=0; ii<NRRD_SPACE_DIM_MAX8; ii++) { | |||
213 | dest->spaceDirection[ii] = src->spaceDirection[ii]; | |||
214 | } | |||
215 | } | |||
216 | if (!(NRRD_AXIS_INFO_CENTER_BIT(1<< 7) & bitflag)) { | |||
217 | dest->center = src->center; | |||
218 | } | |||
219 | if (!(NRRD_AXIS_INFO_KIND_BIT(1<< 8) & bitflag)) { | |||
220 | dest->kind = src->kind; | |||
221 | } | |||
222 | if (!(NRRD_AXIS_INFO_LABEL_BIT(1<< 9) & bitflag)) { | |||
223 | if (dest->label != src->label) { | |||
224 | dest->label = (char *)airFree(dest->label); | |||
225 | dest->label = (char *)airStrdup(src->label); | |||
226 | } | |||
227 | } | |||
228 | if (!(NRRD_AXIS_INFO_UNITS_BIT(1<<10) & bitflag)) { | |||
229 | 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 | } | |||
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 | NrrdAxisInfo axisBuffer[NRRD_DIM_MAX16]; | |||
263 | const NrrdAxisInfo *axis; | |||
264 | unsigned int from, axi; | |||
265 | ||||
266 | if (!(nout && nin)) { | |||
267 | return 1; | |||
268 | } | |||
269 | if (axmap) { | |||
270 | for (axi=0; axi<nout->dim; axi++) { | |||
271 | if (-1 == axmap[axi]) { | |||
272 | continue; | |||
273 | } | |||
274 | if (!AIR_IN_CL(0, axmap[axi], (int)nin->dim-1)((0) <= (axmap[axi]) && (axmap[axi]) <= ((int)nin ->dim-1))) { | |||
275 | return 3; | |||
276 | } | |||
277 | } | |||
278 | } | |||
279 | 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 | axis = nin->axis; | |||
288 | } | |||
289 | for (axi=0; axi<nout->dim; axi++) { | |||
290 | if (axmap && -1 == axmap[axi]) { | |||
291 | /* for this axis, we don't touch a thing */ | |||
292 | continue; | |||
293 | } | |||
294 | from = axmap ? (unsigned int)axmap[axi] : axi; | |||
295 | _nrrdAxisInfoCopy(nout->axis + axi, axis + from, bitflag); | |||
296 | } | |||
297 | if (nout == nin) { | |||
298 | /* free dynamically allocated stuff */ | |||
299 | for (axi=0; axi<nin->dim; axi++) { | |||
300 | _nrrdAxisInfoInit(axisBuffer + axi); | |||
301 | } | |||
302 | } | |||
303 | return 0; | |||
304 | } | |||
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 | if (!( nrrd | |||
334 | && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)((1) <= (nrrd->dim) && (nrrd->dim) <= (16 )) | |||
335 | && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast)((nrrdAxisInfoUnknown) < (axInfo) && (axInfo) < (nrrdAxisInfoLast)) | |||
336 | && _info )) { | |||
337 | return; | |||
338 | } | |||
339 | info.P = _info; | |||
340 | ||||
341 | for (ai=0; ai<nrrd->dim; ai++) { | |||
342 | switch (axInfo) { | |||
343 | case nrrdAxisInfoSize: | |||
344 | nrrd->axis[ai].size = info.ST[ai]; | |||
345 | 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 | nrrd->axis[ai].min = info.D[ai]; | |||
354 | break; | |||
355 | case nrrdAxisInfoMax: | |||
356 | nrrd->axis[ai].max = info.D[ai]; | |||
357 | break; | |||
358 | case nrrdAxisInfoSpaceDirection: | |||
359 | /* we won't allow setting an invalid direction */ | |||
360 | exists = AIR_EXISTS(info.V[ai][0])(((int)(!((info.V[ai][0]) - (info.V[ai][0]))))); | |||
361 | minsi = nrrd->spaceDim; | |||
362 | for (si=0; si<nrrd->spaceDim; si++) { | |||
363 | nrrd->axis[ai].spaceDirection[si] = info.V[ai][si]; | |||
364 | if (exists ^ AIR_EXISTS(info.V[ai][si])(((int)(!((info.V[ai][si]) - (info.V[ai][si])))))) { | |||
365 | minsi = 0; | |||
366 | break; | |||
367 | } | |||
368 | } | |||
369 | for (si=minsi; si<NRRD_SPACE_DIM_MAX8; si++) { | |||
370 | nrrd->axis[ai].spaceDirection[si] = AIR_NAN(airFloatQNaN.f); | |||
371 | } | |||
372 | break; | |||
373 | case nrrdAxisInfoCenter: | |||
374 | nrrd->axis[ai].center = info.I[ai]; | |||
375 | break; | |||
376 | case nrrdAxisInfoKind: | |||
377 | nrrd->axis[ai].kind = info.I[ai]; | |||
378 | break; | |||
379 | case nrrdAxisInfoLabel: | |||
380 | nrrd->axis[ai].label = (char *)airFree(nrrd->axis[ai].label); | |||
381 | nrrd->axis[ai].label = (char *)airStrdup(info.CP[ai]); | |||
382 | 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 | if (nrrdAxisInfoSpaceDirection == axInfo) { | |||
390 | for (ai=nrrd->dim; ai<NRRD_DIM_MAX16; ai++) { | |||
391 | for (si=0; si<NRRD_SPACE_DIM_MAX8; si++) { | |||
392 | nrrd->axis[ai].spaceDirection[si] = AIR_NAN(airFloatQNaN.f); | |||
393 | } | |||
394 | } | |||
395 | } | |||
396 | return; | |||
397 | } | |||
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 | NRRD_TYPE_BIGGESTdouble *buffer[NRRD_DIM_MAX16]; | |||
419 | _nrrdAxisInfoSetPtrs info; | |||
420 | unsigned int ai, si; | |||
421 | va_list ap; | |||
422 | double *dp, svec[NRRD_DIM_MAX16][NRRD_SPACE_DIM_MAX8]; | |||
423 | ||||
424 | if (!( nrrd | |||
425 | && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)((1) <= (nrrd->dim) && (nrrd->dim) <= (16 )) | |||
426 | && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast)((nrrdAxisInfoUnknown) < (axInfo) && (axInfo) < (nrrdAxisInfoLast)) )) { | |||
427 | return; | |||
428 | } | |||
429 | ||||
430 | info.P = buffer; | |||
431 | va_start(ap, axInfo)__builtin_va_start(ap, axInfo); | |||
432 | for (ai=0; ai<nrrd->dim; ai++) { | |||
433 | switch (axInfo) { | |||
434 | case nrrdAxisInfoSize: | |||
435 | info.ST[ai] = va_arg(ap, size_t)__builtin_va_arg(ap, size_t); | |||
436 | /* | |||
437 | printf("!%s: got int[%d] = %d\n", "nrrdAxisInfoSet", d, info.I[ai]); | |||
438 | */ | |||
439 | break; | |||
440 | case nrrdAxisInfoSpaceDirection: | |||
441 | dp = va_arg(ap, double*)__builtin_va_arg(ap, double*); /* punting on using info enum */ | |||
442 | /* | |||
443 | printf("!%s: got dp = %lu\n", "nrrdAxisInfoSet", | |||
444 | (unsigned long)(dp)); | |||
445 | */ | |||
446 | for (si=0; si<nrrd->spaceDim; si++) { | |||
447 | /* nrrd->axis[ai].spaceDirection[si] = dp[si]; */ | |||
448 | svec[ai][si] = dp[si]; | |||
449 | } | |||
450 | for (si=nrrd->spaceDim; si<NRRD_SPACE_DIM_MAX8; si++) { | |||
451 | /* nrrd->axis[ai].spaceDirection[si] = AIR_NAN; */ | |||
452 | svec[ai][si] = dp[si]; | |||
453 | } | |||
454 | break; | |||
455 | case nrrdAxisInfoCenter: | |||
456 | case nrrdAxisInfoKind: | |||
457 | info.I[ai] = va_arg(ap, int)__builtin_va_arg(ap, int); | |||
458 | /* | |||
459 | printf("!%s: got int[%d] = %d\n", | |||
460 | "nrrdAxisInfoSet", d, info.I[ai]); | |||
461 | */ | |||
462 | break; | |||
463 | case nrrdAxisInfoSpacing: | |||
464 | case nrrdAxisInfoThickness: | |||
465 | case nrrdAxisInfoMin: | |||
466 | case nrrdAxisInfoMax: | |||
467 | info.D[ai] = va_arg(ap, double)__builtin_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 | info.CP[ai] = va_arg(ap, char *)__builtin_va_arg(ap, char *); | |||
478 | /* | |||
479 | printf("!%s: got char*[%d] = |%s|\n", | |||
480 | "nrrdAxisInfoSet", d, info.CP[ai]); | |||
481 | */ | |||
482 | break; | |||
483 | case nrrdAxisInfoUnits: | |||
484 | /* see not above */ | |||
485 | info.CP[ai] = va_arg(ap, char *)__builtin_va_arg(ap, char *); | |||
486 | break; | |||
487 | } | |||
488 | } | |||
489 | va_end(ap)__builtin_va_end(ap); | |||
490 | ||||
491 | if (nrrdAxisInfoSpaceDirection != axInfo) { | |||
492 | /* now set the quantities which we've gotten from the var args */ | |||
493 | nrrdAxisInfoSet_nva(nrrd, axInfo, info.P); | |||
494 | } else { | |||
495 | nrrdAxisInfoSet_nva(nrrd, axInfo, svec); | |||
496 | } | |||
497 | ||||
498 | return; | |||
499 | } | |||
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 | if (!( nrrd | |||
528 | && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)((1) <= (nrrd->dim) && (nrrd->dim) <= (16 )) | |||
529 | && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast)((nrrdAxisInfoUnknown) < (axInfo) && (axInfo) < (nrrdAxisInfoLast)) )) { | |||
530 | return; | |||
531 | } | |||
532 | ||||
533 | info.P = _info; | |||
534 | for (ai=0; ai<nrrd->dim; ai++) { | |||
535 | switch (axInfo) { | |||
536 | case nrrdAxisInfoSize: | |||
537 | info.ST[ai] = nrrd->axis[ai].size; | |||
538 | break; | |||
539 | case nrrdAxisInfoSpacing: | |||
540 | info.D[ai] = nrrd->axis[ai].spacing; | |||
541 | break; | |||
542 | case nrrdAxisInfoThickness: | |||
543 | info.D[ai] = nrrd->axis[ai].thickness; | |||
544 | break; | |||
545 | case nrrdAxisInfoMin: | |||
546 | info.D[ai] = nrrd->axis[ai].min; | |||
547 | break; | |||
548 | case nrrdAxisInfoMax: | |||
549 | info.D[ai] = nrrd->axis[ai].max; | |||
550 | 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_MAX8; si++) { | |||
556 | info.V[ai][si] = AIR_NAN(airFloatQNaN.f); | |||
557 | } | |||
558 | break; | |||
559 | case nrrdAxisInfoCenter: | |||
560 | info.I[ai] = nrrd->axis[ai].center; | |||
561 | break; | |||
562 | case nrrdAxisInfoKind: | |||
563 | info.I[ai] = nrrd->axis[ai].kind; | |||
564 | 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 | if (nrrdAxisInfoSpaceDirection == axInfo) { | |||
576 | for (ai=nrrd->dim; ai<NRRD_DIM_MAX16; ai++) { | |||
577 | for (si=0; si<NRRD_SPACE_DIM_MAX8; si++) { | |||
578 | info.V[ai][si] = AIR_NAN(airFloatQNaN.f); | |||
579 | } | |||
580 | } | |||
581 | } | |||
582 | return; | |||
583 | } | |||
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_MAX16], *ptr; | |||
601 | _nrrdAxisInfoGetPtrs info; | |||
602 | unsigned int ai, si; | |||
603 | va_list ap; | |||
604 | double svec[NRRD_DIM_MAX16][NRRD_SPACE_DIM_MAX8]; | |||
605 | ||||
606 | if (!( nrrd | |||
607 | && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)((1) <= (nrrd->dim) && (nrrd->dim) <= (16 )) | |||
608 | && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast)((nrrdAxisInfoUnknown) < (axInfo) && (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)__builtin_va_start(ap, axInfo); | |||
620 | for (ai=0; ai<nrrd->dim; ai++) { | |||
621 | ptr = va_arg(ap, void*)__builtin_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_MAX8; si++) { | |||
643 | ((double*)ptr)[si] = AIR_NAN(airFloatQNaN.f); | |||
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)__builtin_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 | center = (nrrdCenterUnknown == center | |||
681 | ? nrrdDefaultCenter | |||
682 | : center); | |||
683 | center = AIR_CLAMP(nrrdCenterUnknown+1, center, nrrdCenterLast-1)((center) < (nrrdCenterUnknown+1) ? (nrrdCenterUnknown+1) : ((center) > (nrrdCenterLast-1) ? (nrrdCenterLast-1) : (center ))); | |||
684 | 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)((center) < (nrrdCenterUnknown+1) ? (nrrdCenterUnknown+1) : ((center) > (nrrdCenterLast-1) ? (nrrdCenterLast-1) : (center ))); | |||
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 | if (!( nrrd && ax <= nrrd->dim-1 )) { | |||
714 | return AIR_NAN(airFloatQNaN.f); | |||
715 | } | |||
716 | center = _nrrdCenter(nrrd->axis[ax].center); | |||
717 | min = nrrd->axis[ax].min; | |||
718 | max = nrrd->axis[ax].max; | |||
719 | size = nrrd->axis[ax].size; | |||
720 | ||||
721 | return NRRD_POS(center, min, max, size, idx)(nrrdCenterCell == (center) ? ( ((double)(((max)))-(((min)))) *((double)(((idx)) + 0.5)-(0)) / ((double)(((size)))-(0)) + ( ((min)))) : ( ((double)(((max)))-(((min))))*((double)(((idx)) )-(0)) / ((double)(((size))-1)-(0)) + (((min))))); | |||
722 | } | |||
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(airFloatQNaN.f); | |||
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)(nrrdCenterCell == (center) ? (( ((double)(((size)))-(0))*((double )(((pos)))-(((min)))) / ((double)(((max)))-(((min)))) + (0)) - 0.5) : ( ((double)(((size))-1)-(0))*((double)(((pos)))-(((min )))) / ((double)(((max)))-(((min)))) + (0))); | |||
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 | if (!( loP && hiP && nrrd && ax <= nrrd->dim-1 )) { | |||
766 | if (loP) *loP = AIR_NAN(airFloatQNaN.f); | |||
767 | if (hiP) *hiP = AIR_NAN(airFloatQNaN.f); | |||
768 | return; | |||
769 | } | |||
770 | center = _nrrdCenter(nrrd->axis[ax].center); | |||
771 | min = nrrd->axis[ax].min; | |||
772 | max = nrrd->axis[ax].max; | |||
773 | size = nrrd->axis[ax].size; | |||
774 | ||||
775 | if (loIdx > hiIdx) { | |||
776 | flip = 1; | |||
777 | tmp = loIdx; loIdx = hiIdx; hiIdx = tmp; | |||
778 | } | |||
779 | if (nrrdCenterCell == center) { | |||
780 | *loP = AIR_AFFINE(0, loIdx, size, min, max)( ((double)(max)-(min))*((double)(loIdx)-(0)) / ((double)(size )-(0)) + (min)); | |||
781 | *hiP = AIR_AFFINE(0, hiIdx+1, size, min, max)( ((double)(max)-(min))*((double)(hiIdx+1)-(0)) / ((double)(size )-(0)) + (min)); | |||
782 | } else { | |||
783 | *loP = AIR_AFFINE(0, loIdx, size-1, min, max)( ((double)(max)-(min))*((double)(loIdx)-(0)) / ((double)(size -1)-(0)) + (min)); | |||
784 | *hiP = AIR_AFFINE(0, hiIdx, size-1, min, max)( ((double)(max)-(min))*((double)(hiIdx)-(0)) / ((double)(size -1)-(0)) + (min)); | |||
785 | } | |||
786 | if (flip) { | |||
787 | tmp = *loP; *loP = *hiP; *hiP = tmp; | |||
788 | } | |||
789 | ||||
790 | return; | |||
791 | } | |||
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(airFloatQNaN.f); | |||
| ||||
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)( ((double)(size)-(0))*((double)(loPos)-(min)) / ((double)(max )-(min)) + (0)); | |||
834 | *hiP = AIR_AFFINE(min, hiPos, max, -1, size-1)( ((double)(size-1)-(-1))*((double)(hiPos)-(min)) / ((double) (max)-(min)) + (-1)); | |||
835 | } else { | |||
836 | *loP = AIR_AFFINE(min, loPos, max, -1, size-1)( ((double)(size-1)-(-1))*((double)(loPos)-(min)) / ((double) (max)-(min)) + (-1)); | |||
837 | *hiP = AIR_AFFINE(min, hiPos, max, 0, size)( ((double)(size)-(0))*((double)(hiPos)-(min)) / ((double)(max )-(min)) + (0)); | |||
838 | } | |||
839 | } else { | |||
840 | *loP = AIR_AFFINE(min, loPos, max, 0, size-1)( ((double)(size-1)-(0))*((double)(loPos)-(min)) / ((double)( max)-(min)) + (0)); | |||
841 | *hiP = AIR_AFFINE(min, hiPos, max, 0, size-1)( ((double)(size-1)-(0))*((double)(hiPos)-(min)) / ((double)( max)-(min)) + (0)); | |||
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)(((int)(!((min) - (min))))) && AIR_EXISTS(max)(((int)(!((max) - (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),(nrrdCenterCell == _nrrdCenter(nrrd->axis[ax].center) ? (( max) - (min))/((double)(nrrd->axis[ax].size)) : ((max) - ( min))/(((double)((nrrd->axis[ax].size)- 1)))) | |||
877 | min, max, nrrd->axis[ax].size)(nrrdCenterCell == _nrrdCenter(nrrd->axis[ax].center) ? (( max) - (min))/((double)(nrrd->axis[ax].size)) : ((max) - ( min))/(((double)((nrrd->axis[ax].size)- 1)))); | |||
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)(((int)(!((spacing) - (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)((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)((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 | nna = AIR_EXISTS(aa)(((int)(!((aa) - (aa))))) || !airIsNaN(aa); | |||
919 | nnb = AIR_EXISTS(bb)(((int)(!((bb) - (bb))))) || !airIsNaN(bb); | |||
920 | if (nna && nnb) { | |||
921 | /* both either exist or are an infinity */ | |||
922 | ret = (aa < bb | |||
923 | ? -1 | |||
924 | : (aa > bb | |||
925 | ? 1 | |||
926 | : 0)); | |||
927 | } else { | |||
928 | /* one or the other is NaN */ | |||
929 | ret = (nna < nnb | |||
930 | ? -1 | |||
931 | : (nna > nnb | |||
932 | ? 1 | |||
933 | : 0)); | |||
934 | } | |||
935 | 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(512+1)]) { | |||
951 | static const char me[]="nrrdAxisInfoCompare"; | |||
952 | unsigned int saxi; | |||
953 | ||||
954 | if (!(axisA && axisB && differ)) { | |||
955 | biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer (%p, %p, or %p)", me, | |||
956 | AIR_CVOIDP(axisA)((const void *)(axisA)), AIR_CVOIDP(axisB)((const void *)(axisB)), AIR_VOIDP(differ)((void *)(differ))); | |||
957 | return 1; | |||
958 | } | |||
959 | ||||
960 | if (explain) { | |||
961 | strcpy(explain, "")__builtin___strcpy_chk (explain, "", __builtin_object_size (explain , 2 > 1 ? 1 : 0)); | |||
962 | } | |||
963 | if (axisA->size != axisB->size) { | |||
964 | char stmp1[AIR_STRLEN_SMALL(128+1)], stmp2[AIR_STRLEN_SMALL(128+1)]; | |||
965 | *differ = axisA->size < axisB->size ? -1 : 1; | |||
966 | if (explain) { | |||
967 | sprintf(explain, "axisA->size=%s %s axisB->size=%s",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->size=%s %s axisB->size=%s" , airSprintSize_t(stmp1, axisA->size), *differ < 0 ? "<" : ">", airSprintSize_t(stmp2, axisB->size)) | |||
968 | airSprintSize_t(stmp1, axisA->size),__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->size=%s %s axisB->size=%s" , airSprintSize_t(stmp1, axisA->size), *differ < 0 ? "<" : ">", airSprintSize_t(stmp2, axisB->size)) | |||
969 | *differ < 0 ? "<" : ">",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->size=%s %s axisB->size=%s" , airSprintSize_t(stmp1, axisA->size), *differ < 0 ? "<" : ">", airSprintSize_t(stmp2, axisB->size)) | |||
970 | airSprintSize_t(stmp2, axisB->size))__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->size=%s %s axisB->size=%s" , airSprintSize_t(stmp1, axisA->size), *differ < 0 ? "<" : ">", 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", \__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->%s %.17g %s axisB->%s %.17g" , STR, axisA->VAL, *differ < 0 ? "<" : ">", STR, axisB ->VAL) | |||
980 | STR, axisA->VAL, *differ < 0 ? "<" : ">", \__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->%s %.17g %s axisB->%s %.17g" , STR, axisA->VAL, *differ < 0 ? "<" : ">", STR, axisB ->VAL) | |||
981 | STR, axisB->VAL)__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->%s %.17g %s axisB->%s %.17g" , STR, axisA->VAL, *differ < 0 ? "<" : ">", STR, axisB ->VAL); \ | |||
982 | } \ | |||
983 | return 0; \ | |||
984 | } | |||
985 | ||||
986 | DOUBLE_COMPARE(spacing, "spacing"); | |||
987 | DOUBLE_COMPARE(thickness, "thickness"); | |||
988 | DOUBLE_COMPARE(min, "min"); | |||
989 | DOUBLE_COMPARE(max, "max"); | |||
990 | for (saxi=0; saxi<NRRD_SPACE_DIM_MAX8; saxi++) { | |||
991 | char stmp[AIR_STRLEN_SMALL(128+1)]; | |||
992 | sprintf(stmp, "spaceDirection[%u]", saxi)__builtin___sprintf_chk (stmp, 0, __builtin_object_size (stmp , 2 > 1 ? 1 : 0), "spaceDirection[%u]", saxi); | |||
993 | DOUBLE_COMPARE(spaceDirection[saxi], stmp); | |||
994 | } | |||
995 | #undef DOUBLE_COMPARE | |||
996 | ||||
997 | 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",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->center %s %s axisB->center %s" , airEnumStr(nrrdCenter, axisA->center), *differ < 0 ? "<" : ">", airEnumStr(nrrdCenter, axisB->center)) | |||
1001 | airEnumStr(nrrdCenter, axisA->center),__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->center %s %s axisB->center %s" , airEnumStr(nrrdCenter, axisA->center), *differ < 0 ? "<" : ">", airEnumStr(nrrdCenter, axisB->center)) | |||
1002 | *differ < 0 ? "<" : ">",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->center %s %s axisB->center %s" , airEnumStr(nrrdCenter, axisA->center), *differ < 0 ? "<" : ">", airEnumStr(nrrdCenter, axisB->center)) | |||
1003 | airEnumStr(nrrdCenter, axisB->center))__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->center %s %s axisB->center %s" , airEnumStr(nrrdCenter, axisA->center), *differ < 0 ? "<" : ">", airEnumStr(nrrdCenter, axisB->center)); | |||
1004 | } | |||
1005 | return 0; | |||
1006 | } | |||
1007 | 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",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->kind %s %s axisB->kind %s" , airEnumStr(nrrdKind, axisA->kind), *differ < 0 ? "<" : ">", airEnumStr(nrrdKind, axisB->kind)) | |||
1011 | airEnumStr(nrrdKind, axisA->kind),__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->kind %s %s axisB->kind %s" , airEnumStr(nrrdKind, axisA->kind), *differ < 0 ? "<" : ">", airEnumStr(nrrdKind, axisB->kind)) | |||
1012 | *differ < 0 ? "<" : ">",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->kind %s %s axisB->kind %s" , airEnumStr(nrrdKind, axisA->kind), *differ < 0 ? "<" : ">", airEnumStr(nrrdKind, axisB->kind)) | |||
1013 | airEnumStr(nrrdKind, axisB->kind))__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->kind %s %s axisB->kind %s" , airEnumStr(nrrdKind, axisA->kind), *differ < 0 ? "<" : ">", airEnumStr(nrrdKind, axisB->kind)); | |||
1014 | } | |||
1015 | return 0; | |||
1016 | } | |||
1017 | *differ = airStrcmp(axisA->label, axisB->label); | |||
1018 | 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",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->label %s axisB->label", *differ < 0 ? "<" : ">") | |||
1022 | *differ < 0 ? "<" : ">")__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->label %s axisB->label", *differ < 0 ? "<" : ">"); | |||
1023 | if (strlen(explain) + airStrlen(axisA->label) | |||
1024 | + airStrlen(axisB->label) | |||
1025 | + 2*strlen(" \"\" ") + 1 < AIR_STRLEN_LARGE(512+1)) { | |||
1026 | /* ok, we can print them */ | |||
1027 | sprintf(explain, "axisA->label \"%s\" %s axisB->label \"%s\"",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->label \"%s\" %s axisB->label \"%s\"" , axisA->label ? axisA->label : "", *differ < 0 ? "<" : ">", axisB->label ? axisB->label : "") | |||
1028 | axisA->label ? axisA->label : "",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->label \"%s\" %s axisB->label \"%s\"" , axisA->label ? axisA->label : "", *differ < 0 ? "<" : ">", axisB->label ? axisB->label : "") | |||
1029 | *differ < 0 ? "<" : ">",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->label \"%s\" %s axisB->label \"%s\"" , axisA->label ? axisA->label : "", *differ < 0 ? "<" : ">", axisB->label ? axisB->label : "") | |||
1030 | axisB->label ? axisB->label : "")__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->label \"%s\" %s axisB->label \"%s\"" , axisA->label ? axisA->label : "", *differ < 0 ? "<" : ">", axisB->label ? axisB->label : ""); | |||
1031 | } | |||
1032 | } | |||
1033 | return 0; | |||
1034 | } | |||
1035 | *differ = airStrcmp(axisA->units, axisB->units); | |||
1036 | 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",__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->units %s axisB->units", *differ < 0 ? "<" : ">") | |||
1040 | *differ < 0 ? "<" : ">")__builtin___sprintf_chk (explain, 0, __builtin_object_size (explain , 2 > 1 ? 1 : 0), "axisA->units %s axisB->units", *differ < 0 ? "<" : ">"); | |||
1041 | } | |||
1042 | return 0; | |||
1043 | } | |||
1044 | ||||
1045 | return 0; | |||
1046 | } | |||
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_MAX16]) { | |||
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 | if (!( nrrd && axi < nrrd->dim && nrrd->spaceDim )) { | |||
1084 | ret = AIR_FALSE0; | |||
1085 | } else { | |||
1086 | ret = AIR_TRUE1; | |||
1087 | for (sai=0; sai<nrrd->spaceDim; sai++) { | |||
1088 | ret &= AIR_EXISTS(nrrd->axis[axi].spaceDirection[sai])(((int)(!((nrrd->axis[axi].spaceDirection[sai]) - (nrrd-> axis[axi].spaceDirection[sai]))))); | |||
1089 | } | |||
1090 | } | |||
1091 | return ret; | |||
1092 | } | |||
1093 | ||||
1094 | unsigned int | |||
1095 | nrrdSpatialAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX16]) { | |||
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_MAX16]) { | |||
1124 | unsigned int domNum, domIdx[NRRD_DIM_MAX16], 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_FALSE0; | |||
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_MAX16]) { | |||
1145 | unsigned int spcNum, spcIdx[NRRD_DIM_MAX16], 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_FALSE0; | |||
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_MAX8]) { | |||
1211 | int ret; | |||
1212 | ||||
1213 | if (!( nrrd && spacing && vector | |||
1214 | && ax <= nrrd->dim-1 | |||
1215 | && !_nrrdCheck(nrrd, AIR_FALSE0, AIR_FALSE0) )) { | |||
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(airFloatQNaN.f); | |||
1221 | } | |||
1222 | if (vector) { | |||
1223 | nrrdSpaceVecSetNaN(vector); | |||
1224 | } | |||
1225 | } else { | |||
1226 | if (AIR_EXISTS(nrrd->axis[ax].spacing)(((int)(!((nrrd->axis[ax].spacing) - (nrrd->axis[ax].spacing )))))) { | |||
1227 | 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 | if (nrrd->spaceDim > 0 && _nrrdSpaceVecExists(nrrd, ax)) { | |||
1236 | ret = nrrdSpacingStatusDirection; | |||
1237 | *spacing = nrrdSpaceVecNorm(nrrd->spaceDim, | |||
1238 | nrrd->axis[ax].spaceDirection); | |||
1239 | nrrdSpaceVecScale(vector, 1.0/(*spacing), | |||
1240 | nrrd->axis[ax].spaceDirection); | |||
1241 | } else { | |||
1242 | ret = nrrdSpacingStatusNone; | |||
1243 | *spacing = AIR_NAN(airFloatQNaN.f); | |||
1244 | nrrdSpaceVecSetNaN(vector); | |||
1245 | } | |||
1246 | } | |||
1247 | } | |||
1248 | 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_MAX16], saxii; | |||
1256 | NrrdAxisInfo *axis; | |||
1257 | ||||
1258 | if (!(nout && nin)) { | |||
1259 | biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me); | |||
1260 | return 1; | |||
1261 | } | |||
1262 | ||||
1263 | if (nout != nin) { | |||
1264 | if (nrrdCopy(nout, nin)) { | |||
1265 | biffAddf(NRRDnrrdBiffKey, "%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(airFloatQNaN.f)); | |||
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_MAX16]; | |||
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(NRRDnrrdBiffKey, "%s: got NULL pointer", me); | |||
1315 | return 1; | |||
1316 | } | |||
1317 | if (airEnumValCheck(nrrdMetaDataCanonicalVersion, version)) { | |||
1318 | biffAddf(NRRDnrrdBiffKey, "%s: version %d not valid %s", me, | |||
1319 | version, nrrdMetaDataCanonicalVersion->name); | |||
1320 | return 1; | |||
1321 | } | |||
1322 | if (nrrdMetaDataCanonicalVersionAlpha != version) { | |||
1323 | biffAddf(NRRDnrrdBiffKey, "%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_FALSE0 /* checkData */, AIR_TRUE1 /* useBiff */)) { | |||
1332 | biffAddf(NRRDnrrdBiffKey, "%s: basic check failed", me); | |||
1333 | return 1; | |||
1334 | } | |||
1335 | /* but can't deal with block type */ | |||
1336 | if (nrrdTypeBlock == nin->type) { | |||
1337 | biffAddf(NRRDnrrdBiffKey, "%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_TRUE1; | |||
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)(((int)(!((nin->axis[axi].min) - (nin->axis[axi].min))) )); | |||
1352 | haveMM &= AIR_EXISTS(nin->axis[axi].max)(((int)(!((nin->axis[axi].max) - (nin->axis[axi].max))) )); | |||
1353 | } else { | |||
1354 | if (nrrdKindUnknown != kindIn) { | |||
1355 | biffAddf(NRRDnrrdBiffKey, "%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(NRRDnrrdBiffKey, "%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(NRRDnrrdBiffKey, "%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(NRRDnrrdBiffKey, "%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(NRRDnrrdBiffKey, "%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((void*)0), nin->type, nin->dim, size)) { | |||
1441 | biffAddf(NRRDnrrdBiffKey, "%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((void*)0), NRRD_AXIS_INFO_SIZE_BIT(1<< 1)); | |||
1446 | if (nrrdBasicInfoCopy(ntmp, nin, NRRD_BASIC_INFO_DATA_BIT(1<< 1))) { | |||
1447 | biffAddf(NRRDnrrdBiffKey, "%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_FALSE0; | |||
1456 | for (si=0; si<NRRD_SPACE_DIM_MAX8; si++) { | |||
1457 | for (sj=0; sj<NRRD_SPACE_DIM_MAX8; sj++) { | |||
1458 | gotmf |= AIR_EXISTS(ntmp->measurementFrame[si][sj])(((int)(!((ntmp->measurementFrame[si][sj]) - (ntmp->measurementFrame [si][sj]))))); | |||
1459 | } | |||
1460 | } | |||
1461 | if (lostMeasurementFrame) { | |||
1462 | *lostMeasurementFrame = gotmf; | |||
1463 | } | |||
1464 | for (si=0; si<NRRD_SPACE_DIM_MAX8; si++) { | |||
1465 | for (sj=0; sj<NRRD_SPACE_DIM_MAX8; sj++) { | |||
1466 | ntmp->measurementFrame[si][sj] = AIR_NAN(airFloatQNaN.f); | |||
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(airFloatQNaN.f); | |||
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(airFloatQNaN.f); | |||
1494 | ntmp->axis[axi].max = AIR_NAN(airFloatQNaN.f); | |||
1495 | ntmp->axis[axi].spacing = AIR_NAN(airFloatQNaN.f); | |||
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)(((int)(!((nin->axis[axi].spacing) - (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(NRRDnrrdBiffKey, "%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_MAX8]; | |||
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(NRRDnrrdBiffKey, "%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(NRRDnrrdBiffKey, "%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 |