| 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 |