PageRenderTime 39ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/Modules/ThirdParty/NrrdIO/src/NrrdIO/axis.c

https://github.com/paniwani/ITK
C | 1142 lines | 745 code | 83 blank | 314 comment | 183 complexity | bd034d8d53f7c44bb0dddcac67ed49fb MD5 | raw file
  1. /*
  2. NrrdIO: stand-alone code for basic nrrd functionality
  3. Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann
  4. Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah
  5. This software is provided 'as-is', without any express or implied
  6. warranty. In no event will the authors be held liable for any
  7. damages arising from the use of this software.
  8. Permission is granted to anyone to use this software for any
  9. purpose, including commercial applications, and to alter it and
  10. redistribute it freely, subject to the following restrictions:
  11. 1. The origin of this software must not be misrepresented; you must
  12. not claim that you wrote the original software. If you use this
  13. software in a product, an acknowledgment in the product
  14. documentation would be appreciated but is not required.
  15. 2. Altered source versions must be plainly marked as such, and must
  16. not be misrepresented as being the original software.
  17. 3. This notice may not be removed or altered from any source distribution.
  18. */
  19. #include "NrrdIO.h"
  20. #include "privateNrrd.h"
  21. /* ------------------------------------------------------------ */
  22. void
  23. _nrrdAxisInfoInit(NrrdAxisInfo *axis) {
  24. int dd;
  25. if (axis) {
  26. axis->size = 0;
  27. axis->spacing = axis->thickness = AIR_NAN;
  28. axis->min = axis->max = AIR_NAN;
  29. for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
  30. axis->spaceDirection[dd] = AIR_NAN;
  31. }
  32. axis->center = nrrdCenterUnknown;
  33. axis->kind = nrrdKindUnknown;
  34. axis->label = (char *)airFree(axis->label);
  35. axis->units = (char *)airFree(axis->units);
  36. }
  37. }
  38. void
  39. _nrrdAxisInfoNewInit(NrrdAxisInfo *axis) {
  40. if (axis) {
  41. axis->label = NULL;
  42. axis->units = NULL;
  43. _nrrdAxisInfoInit(axis);
  44. }
  45. }
  46. /* ------------------------------------------------------------ */
  47. /*
  48. ******** nrrdKindIsDomain
  49. **
  50. ** returns non-zero for kinds (from nrrdKind* enum) that are domain
  51. ** axes, or independent variable axes, or resample-able axes, all
  52. ** different ways of describing the same thing
  53. */
  54. int
  55. nrrdKindIsDomain(int kind) {
  56. return (nrrdKindDomain == kind
  57. || nrrdKindSpace == kind
  58. || nrrdKindTime == kind);
  59. }
  60. /*
  61. ******** nrrdKindSize
  62. **
  63. ** returns suggested size (length) of an axis with the given kind, or,
  64. ** 0 if either (1) there is no suggested size because the axis is the
  65. ** kind of an independent or domain variable or (2) the kind is invalid
  66. */
  67. unsigned int
  68. nrrdKindSize(int kind) {
  69. static const char me[]="nrrdKindSize";
  70. int ret;
  71. if (!( AIR_IN_OP(nrrdKindUnknown, kind, nrrdKindLast) )) {
  72. /* they gave us invalid or unknown kind */
  73. return 0;
  74. }
  75. switch (kind) {
  76. case nrrdKindDomain:
  77. case nrrdKindSpace:
  78. case nrrdKindTime:
  79. case nrrdKindList:
  80. case nrrdKindPoint:
  81. case nrrdKindVector:
  82. case nrrdKindCovariantVector:
  83. case nrrdKindNormal:
  84. ret = 0;
  85. break;
  86. case nrrdKindStub:
  87. case nrrdKindScalar:
  88. ret = 1;
  89. break;
  90. case nrrdKindComplex:
  91. case nrrdKind2Vector:
  92. ret = 2;
  93. break;
  94. case nrrdKind3Color:
  95. case nrrdKindRGBColor:
  96. case nrrdKindHSVColor:
  97. case nrrdKindXYZColor:
  98. ret = 3;
  99. break;
  100. case nrrdKind4Color:
  101. case nrrdKindRGBAColor:
  102. ret = 4;
  103. break;
  104. case nrrdKind3Vector:
  105. case nrrdKind3Normal:
  106. ret = 3;
  107. break;
  108. case nrrdKind4Vector:
  109. case nrrdKindQuaternion:
  110. ret = 4;
  111. break;
  112. case nrrdKind2DSymMatrix:
  113. ret = 3;
  114. break;
  115. case nrrdKind2DMaskedSymMatrix:
  116. ret = 4;
  117. break;
  118. case nrrdKind2DMatrix:
  119. ret = 4;
  120. break;
  121. case nrrdKind2DMaskedMatrix:
  122. ret = 5;
  123. break;
  124. case nrrdKind3DSymMatrix:
  125. ret = 6;
  126. break;
  127. case nrrdKind3DMaskedSymMatrix:
  128. ret = 7;
  129. break;
  130. case nrrdKind3DMatrix:
  131. ret = 9;
  132. break;
  133. case nrrdKind3DMaskedMatrix:
  134. ret = 10;
  135. break;
  136. default:
  137. fprintf(stderr, "%s: PANIC: nrrdKind %d not implemented!\n", me, kind);
  138. exit(1);
  139. }
  140. return ret;
  141. }
  142. /*
  143. ** _nrrdKindAltered:
  144. **
  145. ** implements logic for how kind should be updated when samples
  146. ** along the axis are altered
  147. */
  148. int
  149. _nrrdKindAltered(int kindIn, int resampling) {
  150. int kindOut;
  151. if (nrrdStateKindNoop) {
  152. kindOut = nrrdKindUnknown;
  153. /* HEY: setting the kindOut to unknown is arguably not a no-op.
  154. It is more like pointedly and stubbornly simplistic. So maybe
  155. nrrdStateKindNoop could be renamed .. */
  156. } else {
  157. if (nrrdKindIsDomain(kindIn)
  158. || (0 == nrrdKindSize(kindIn) && !resampling)) {
  159. kindOut = kindIn;
  160. } else {
  161. kindOut = nrrdKindUnknown;
  162. }
  163. }
  164. return kindOut;
  165. }
  166. /*
  167. ** _nrrdAxisInfoCopy
  168. **
  169. ** HEY: we have a void return even though this function potentially
  170. ** involves calling airStrdup!!
  171. */
  172. void
  173. _nrrdAxisInfoCopy(NrrdAxisInfo *dest, const NrrdAxisInfo *src, int bitflag) {
  174. int ii;
  175. if (!(NRRD_AXIS_INFO_SIZE_BIT & bitflag)) {
  176. dest->size = src->size;
  177. }
  178. if (!(NRRD_AXIS_INFO_SPACING_BIT & bitflag)) {
  179. dest->spacing = src->spacing;
  180. }
  181. if (!(NRRD_AXIS_INFO_THICKNESS_BIT & bitflag)) {
  182. dest->thickness = src->thickness;
  183. }
  184. if (!(NRRD_AXIS_INFO_MIN_BIT & bitflag)) {
  185. dest->min = src->min;
  186. }
  187. if (!(NRRD_AXIS_INFO_MAX_BIT & bitflag)) {
  188. dest->max = src->max;
  189. }
  190. if (!(NRRD_AXIS_INFO_SPACEDIRECTION_BIT & bitflag)) {
  191. for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) {
  192. dest->spaceDirection[ii] = src->spaceDirection[ii];
  193. }
  194. }
  195. if (!(NRRD_AXIS_INFO_CENTER_BIT & bitflag)) {
  196. dest->center = src->center;
  197. }
  198. if (!(NRRD_AXIS_INFO_KIND_BIT & bitflag)) {
  199. dest->kind = src->kind;
  200. }
  201. if (!(NRRD_AXIS_INFO_LABEL_BIT & bitflag)) {
  202. if (dest->label != src->label) {
  203. dest->label = (char *)airFree(dest->label);
  204. dest->label = (char *)airStrdup(src->label);
  205. }
  206. }
  207. if (!(NRRD_AXIS_INFO_UNITS_BIT & bitflag)) {
  208. if (dest->units != src->units) {
  209. dest->units = (char *)airFree(dest->units);
  210. dest->units = (char *)airStrdup(src->units);
  211. }
  212. }
  213. return;
  214. }
  215. /*
  216. ******** nrrdAxisInfoCopy()
  217. **
  218. ** For copying all the per-axis peripheral information. Takes a
  219. ** permutation "map"; map[d] tells from which axis in input should the
  220. ** output axis d copy its information. The length of this permutation
  221. ** array is nout->dim. If map is NULL, the identity permutation is
  222. ** assumed. If map[i]==-1 for any i in [0,dim-1], then nothing is
  223. ** copied into axis i of output. The "bitflag" field controls which
  224. ** per-axis fields will NOT be copied; if bitflag==0, then all fields
  225. ** are copied. The value of bitflag should be |'s of NRRD_AXIS_INFO_*
  226. ** defines.
  227. **
  228. ** Decided to Not use Biff, since many times map will be NULL, in
  229. ** which case the only error is getting a NULL nrrd, or an invalid map
  230. ** permutation, which will probably be unlikely given the contexts in
  231. ** which this is called. For the paranoid, the integer return value
  232. ** indicates error.
  233. **
  234. ** Sun Feb 27 21:12:57 EST 2005: decided to allow nout==nin, so now
  235. ** use a local array of NrrdAxisInfo as buffer.
  236. */
  237. int
  238. nrrdAxisInfoCopy(Nrrd *nout, const Nrrd *nin, const int *axmap, int bitflag) {
  239. NrrdAxisInfo axisBuffer[NRRD_DIM_MAX];
  240. const NrrdAxisInfo *axis;
  241. unsigned int from, axi;
  242. if (!(nout && nin)) {
  243. return 1;
  244. }
  245. if (axmap) {
  246. for (axi=0; axi<nout->dim; axi++) {
  247. if (-1 == axmap[axi]) {
  248. continue;
  249. }
  250. if (!AIR_IN_CL(0, axmap[axi], (int)nin->dim-1)) {
  251. return 3;
  252. }
  253. }
  254. }
  255. if (nout == nin) {
  256. /* copy axis info to local buffer */
  257. for (axi=0; axi<nin->dim; axi++) {
  258. _nrrdAxisInfoNewInit(axisBuffer + axi);
  259. _nrrdAxisInfoCopy(axisBuffer + axi, nin->axis + axi, bitflag);
  260. }
  261. axis = axisBuffer;
  262. } else {
  263. axis = nin->axis;
  264. }
  265. for (axi=0; axi<nout->dim; axi++) {
  266. if (axmap && -1 == axmap[axi]) {
  267. /* for this axis, we don't touch a thing */
  268. continue;
  269. }
  270. from = axmap ? (unsigned int)axmap[axi] : axi;
  271. _nrrdAxisInfoCopy(nout->axis + axi, axis + from, bitflag);
  272. }
  273. if (nout == nin) {
  274. /* free dynamically allocated stuff */
  275. for (axi=0; axi<nin->dim; axi++) {
  276. _nrrdAxisInfoInit(axisBuffer + axi);
  277. }
  278. }
  279. return 0;
  280. }
  281. /*
  282. ******** nrrdAxisInfoSet_nva()
  283. **
  284. ** Simple means of setting fields of the axis array in the nrrd.
  285. **
  286. ** type to pass for third argument:
  287. ** nrrdAxisInfoSize: size_t*
  288. ** nrrdAxisInfoSpacing: double*
  289. ** nrrdAxisInfoThickness: double*
  290. ** nrrdAxisInfoMin: double*
  291. ** nrrdAxisInfoMax: double*
  292. ** nrrdAxisInfoSpaceDirection: double (*var)[NRRD_SPACE_DIM_MAX]
  293. ** nrrdAxisInfoCenter: int*
  294. ** nrrdAxisInfoKind: int*
  295. ** nrrdAxisInfoLabel: char**
  296. ** nrrdAxisInfoUnits: char**
  297. */
  298. void
  299. nrrdAxisInfoSet_nva(Nrrd *nrrd, int axInfo, const void *_info) {
  300. _nrrdAxisInfoSetPtrs info;
  301. int exists;
  302. unsigned int ai, si, minsi;
  303. if (!( nrrd
  304. && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)
  305. && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast)
  306. && _info )) {
  307. return;
  308. }
  309. info.P = _info;
  310. for (ai=0; ai<nrrd->dim; ai++) {
  311. switch (axInfo) {
  312. case nrrdAxisInfoSize:
  313. nrrd->axis[ai].size = info.ST[ai];
  314. break;
  315. case nrrdAxisInfoSpacing:
  316. nrrd->axis[ai].spacing = info.D[ai];
  317. break;
  318. case nrrdAxisInfoThickness:
  319. nrrd->axis[ai].thickness = info.D[ai];
  320. break;
  321. case nrrdAxisInfoMin:
  322. nrrd->axis[ai].min = info.D[ai];
  323. break;
  324. case nrrdAxisInfoMax:
  325. nrrd->axis[ai].max = info.D[ai];
  326. break;
  327. case nrrdAxisInfoSpaceDirection:
  328. /* we won't allow setting an invalid direction */
  329. exists = AIR_EXISTS(info.V[ai][0]);
  330. minsi = nrrd->spaceDim;
  331. for (si=0; si<nrrd->spaceDim; si++) {
  332. nrrd->axis[ai].spaceDirection[si] = info.V[ai][si];
  333. if (exists ^ AIR_EXISTS(info.V[ai][si])) {
  334. minsi = 0;
  335. break;
  336. }
  337. }
  338. for (si=minsi; si<NRRD_SPACE_DIM_MAX; si++) {
  339. nrrd->axis[ai].spaceDirection[si] = AIR_NAN;
  340. }
  341. break;
  342. case nrrdAxisInfoCenter:
  343. nrrd->axis[ai].center = info.I[ai];
  344. break;
  345. case nrrdAxisInfoKind:
  346. nrrd->axis[ai].kind = info.I[ai];
  347. break;
  348. case nrrdAxisInfoLabel:
  349. nrrd->axis[ai].label = (char *)airFree(nrrd->axis[ai].label);
  350. nrrd->axis[ai].label = (char *)airStrdup(info.CP[ai]);
  351. break;
  352. case nrrdAxisInfoUnits:
  353. nrrd->axis[ai].units = (char *)airFree(nrrd->axis[ai].units);
  354. nrrd->axis[ai].units = (char *)airStrdup(info.CP[ai]);
  355. break;
  356. }
  357. }
  358. if (nrrdAxisInfoSpaceDirection == axInfo) {
  359. for (ai=nrrd->dim; ai<NRRD_DIM_MAX; ai++) {
  360. for (si=0; si<NRRD_SPACE_DIM_MAX; si++) {
  361. nrrd->axis[ai].spaceDirection[si] = AIR_NAN;
  362. }
  363. }
  364. }
  365. return;
  366. }
  367. /*
  368. ******** nrrdAxisInfoSet_va()
  369. **
  370. ** var args front-end for nrrdAxisInfoSet_nva
  371. **
  372. ** types to pass, one for each dimension:
  373. ** nrrdAxisInfoSize: size_t
  374. ** nrrdAxisInfoSpacing: double
  375. ** nrrdAxisInfoThickness: double
  376. ** nrrdAxisInfoMin: double
  377. ** nrrdAxisInfoMax: double
  378. ** nrrdAxisInfoSpaceDirection: double*
  379. ** nrrdAxisInfoCenter: int
  380. ** nrrdAxisInfoKind: int
  381. ** nrrdAxisInfoLabel: char*
  382. ** nrrdAxisInfoUnits: char*
  383. */
  384. void
  385. nrrdAxisInfoSet_va(Nrrd *nrrd, int axInfo, ...) {
  386. NRRD_TYPE_BIGGEST *buffer[NRRD_DIM_MAX];
  387. _nrrdAxisInfoSetPtrs info;
  388. unsigned int ai, si;
  389. va_list ap;
  390. double *dp, svec[NRRD_DIM_MAX][NRRD_SPACE_DIM_MAX];
  391. if (!( nrrd
  392. && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)
  393. && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) )) {
  394. return;
  395. }
  396. info.P = buffer;
  397. va_start(ap, axInfo);
  398. for (ai=0; ai<nrrd->dim; ai++) {
  399. switch (axInfo) {
  400. case nrrdAxisInfoSize:
  401. info.ST[ai] = va_arg(ap, size_t);
  402. /*
  403. printf("!%s: got int[%d] = %d\n", "nrrdAxisInfoSet", d, info.I[ai]);
  404. */
  405. break;
  406. case nrrdAxisInfoSpaceDirection:
  407. dp = va_arg(ap, double*); /* punting on using info enum */
  408. /*
  409. printf("!%s: got dp = %lu\n", "nrrdAxisInfoSet",
  410. (unsigned long)(dp));
  411. */
  412. for (si=0; si<nrrd->spaceDim; si++) {
  413. /* nrrd->axis[ai].spaceDirection[si] = dp[si]; */
  414. svec[ai][si] = dp[si];
  415. }
  416. for (si=nrrd->spaceDim; si<NRRD_SPACE_DIM_MAX; si++) {
  417. /* nrrd->axis[ai].spaceDirection[si] = AIR_NAN; */
  418. svec[ai][si] = dp[si];
  419. }
  420. break;
  421. case nrrdAxisInfoCenter:
  422. case nrrdAxisInfoKind:
  423. info.I[ai] = va_arg(ap, int);
  424. /*
  425. printf("!%s: got int[%d] = %d\n",
  426. "nrrdAxisInfoSet", d, info.I[ai]);
  427. */
  428. break;
  429. case nrrdAxisInfoSpacing:
  430. case nrrdAxisInfoThickness:
  431. case nrrdAxisInfoMin:
  432. case nrrdAxisInfoMax:
  433. info.D[ai] = va_arg(ap, double);
  434. /*
  435. printf("!%s: got double[%d] = %g\n",
  436. "nrrdAxisInfoSet", d, info.D[ai]);
  437. */
  438. break;
  439. case nrrdAxisInfoLabel:
  440. /* we DO NOT do the airStrdup() here because this pointer value is
  441. just going to be handed to nrrdAxisInfoSet_nva(), which WILL do the
  442. airStrdup(); we're not violating the rules for axis labels */
  443. info.CP[ai] = va_arg(ap, char *);
  444. /*
  445. printf("!%s: got char*[%d] = |%s|\n",
  446. "nrrdAxisInfoSet", d, info.CP[ai]);
  447. */
  448. break;
  449. case nrrdAxisInfoUnits:
  450. /* see not above */
  451. info.CP[ai] = va_arg(ap, char *);
  452. break;
  453. }
  454. }
  455. va_end(ap);
  456. if (nrrdAxisInfoSpaceDirection != axInfo) {
  457. /* now set the quantities which we've gotten from the var args */
  458. nrrdAxisInfoSet_nva(nrrd, axInfo, info.P);
  459. } else {
  460. nrrdAxisInfoSet_nva(nrrd, axInfo, svec);
  461. }
  462. return;
  463. }
  464. /*
  465. ******** nrrdAxisInfoGet_nva()
  466. **
  467. ** get any of the axis fields into an array
  468. **
  469. ** Note that getting axes labels involves implicitly allocating space
  470. ** for them, due to the action of airStrdup(). The user is
  471. ** responsible for free()ing these strings when done with them.
  472. **
  473. ** type to pass for third argument:
  474. ** nrrdAxisInfoSize: size_t*
  475. ** nrrdAxisInfoSpacing: double*
  476. ** nrrdAxisInfoThickness: double*
  477. ** nrrdAxisInfoMin: double*
  478. ** nrrdAxisInfoMax: double*
  479. ** nrrdAxisInfoSpaceDirection: double (*var)[NRRD_SPACE_DIM_MAX]
  480. ** nrrdAxisInfoCenter: int*
  481. ** nrrdAxisInfoKind: int*
  482. ** nrrdAxisInfoLabel: char**
  483. ** nrrdAxisInfoUnits: char**
  484. */
  485. void
  486. nrrdAxisInfoGet_nva(const Nrrd *nrrd, int axInfo, void *_info) {
  487. _nrrdAxisInfoGetPtrs info;
  488. unsigned int ai, si;
  489. if (!( nrrd
  490. && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)
  491. && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) )) {
  492. return;
  493. }
  494. info.P = _info;
  495. for (ai=0; ai<nrrd->dim; ai++) {
  496. switch (axInfo) {
  497. case nrrdAxisInfoSize:
  498. info.ST[ai] = nrrd->axis[ai].size;
  499. break;
  500. case nrrdAxisInfoSpacing:
  501. info.D[ai] = nrrd->axis[ai].spacing;
  502. break;
  503. case nrrdAxisInfoThickness:
  504. info.D[ai] = nrrd->axis[ai].thickness;
  505. break;
  506. case nrrdAxisInfoMin:
  507. info.D[ai] = nrrd->axis[ai].min;
  508. break;
  509. case nrrdAxisInfoMax:
  510. info.D[ai] = nrrd->axis[ai].max;
  511. break;
  512. case nrrdAxisInfoSpaceDirection:
  513. for (si=0; si<nrrd->spaceDim; si++) {
  514. info.V[ai][si] = nrrd->axis[ai].spaceDirection[si];
  515. }
  516. for (si=nrrd->spaceDim; si<NRRD_SPACE_DIM_MAX; si++) {
  517. info.V[ai][si] = AIR_NAN;
  518. }
  519. break;
  520. case nrrdAxisInfoCenter:
  521. info.I[ai] = nrrd->axis[ai].center;
  522. break;
  523. case nrrdAxisInfoKind:
  524. info.I[ai] = nrrd->axis[ai].kind;
  525. break;
  526. case nrrdAxisInfoLabel:
  527. /* note airStrdup()! */
  528. info.CP[ai] = airStrdup(nrrd->axis[ai].label);
  529. break;
  530. case nrrdAxisInfoUnits:
  531. /* note airStrdup()! */
  532. info.CP[ai] = airStrdup(nrrd->axis[ai].units);
  533. break;
  534. }
  535. }
  536. if (nrrdAxisInfoSpaceDirection == axInfo) {
  537. for (ai=nrrd->dim; ai<NRRD_DIM_MAX; ai++) {
  538. for (si=0; si<NRRD_SPACE_DIM_MAX; si++) {
  539. info.V[ai][si] = AIR_NAN;
  540. }
  541. }
  542. }
  543. return;
  544. }
  545. /*
  546. ** types to pass, one for each dimension:
  547. ** nrrdAxisInfoSize: size_t*
  548. ** nrrdAxisInfoSpacing: double*
  549. ** nrrdAxisInfoThickness: double*
  550. ** nrrdAxisInfoMin: double*
  551. ** nrrdAxisInfoMax: double*
  552. ** nrrdAxisInfoSpaceDirection: double*
  553. ** nrrdAxisInfoCenter: int*
  554. ** nrrdAxisInfoKind: int*
  555. ** nrrdAxisInfoLabel: char**
  556. ** nrrdAxisInfoUnits: char**
  557. */
  558. void
  559. nrrdAxisInfoGet_va(const Nrrd *nrrd, int axInfo, ...) {
  560. void *buffer[NRRD_DIM_MAX], *ptr;
  561. _nrrdAxisInfoGetPtrs info;
  562. unsigned int ai, si;
  563. va_list ap;
  564. double svec[NRRD_DIM_MAX][NRRD_SPACE_DIM_MAX];
  565. if (!( nrrd
  566. && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)
  567. && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) )) {
  568. return;
  569. }
  570. if (nrrdAxisInfoSpaceDirection != axInfo) {
  571. info.P = buffer;
  572. nrrdAxisInfoGet_nva(nrrd, axInfo, info.P);
  573. } else {
  574. nrrdAxisInfoGet_nva(nrrd, axInfo, svec);
  575. }
  576. va_start(ap, axInfo);
  577. for (ai=0; ai<nrrd->dim; ai++) {
  578. ptr = va_arg(ap, void*);
  579. /*
  580. printf("!%s(%d): ptr = %lu\n",
  581. "nrrdAxisInfoGet", d, (unsigned long)ptr);
  582. */
  583. switch (axInfo) {
  584. case nrrdAxisInfoSize:
  585. *((size_t*)ptr) = info.ST[ai];
  586. break;
  587. case nrrdAxisInfoSpacing:
  588. case nrrdAxisInfoThickness:
  589. case nrrdAxisInfoMin:
  590. case nrrdAxisInfoMax:
  591. *((double*)ptr) = info.D[ai];
  592. /* printf("!%s: got double[%d] = %lg\n", "nrrdAxisInfoGet", d,
  593. *((double*)ptr)); */
  594. break;
  595. case nrrdAxisInfoSpaceDirection:
  596. for (si=0; si<nrrd->spaceDim; si++) {
  597. ((double*)ptr)[si] = svec[ai][si];
  598. }
  599. for (si=nrrd->spaceDim; si<NRRD_SPACE_DIM_MAX; si++) {
  600. ((double*)ptr)[si] = AIR_NAN;
  601. }
  602. break;
  603. case nrrdAxisInfoCenter:
  604. case nrrdAxisInfoKind:
  605. *((int*)ptr) = info.I[ai];
  606. /* printf("!%s: got int[%d] = %d\n",
  607. "nrrdAxisInfoGet", d, *((int*)ptr)); */
  608. break;
  609. case nrrdAxisInfoLabel:
  610. case nrrdAxisInfoUnits:
  611. /* we DO NOT do the airStrdup() here because this pointer value just
  612. came from nrrdAxisInfoGet_nva(), which already did the airStrdup() */
  613. *((char**)ptr) = info.CP[ai];
  614. /* printf("!%s: got char*[%d] = |%s|\n", "nrrdAxisInfoSet", d,
  615. *((char**)ptr)); */
  616. break;
  617. }
  618. }
  619. va_end(ap);
  620. return;
  621. }
  622. /*
  623. ** _nrrdCenter()
  624. **
  625. ** for nrrdCenterCell and nrrdCenterNode, return will be the same
  626. ** as input. Converts nrrdCenterUnknown into nrrdDefaultCenter,
  627. ** and then clamps to (nrrdCenterUnknown+1, nrrdCenterLast-1).
  628. **
  629. ** Thus, this ALWAYS returns nrrdCenterNode or nrrdCenterCell
  630. ** (as long as those are the only two centering schemes).
  631. */
  632. int
  633. _nrrdCenter(int center) {
  634. center = (nrrdCenterUnknown == center
  635. ? nrrdDefaultCenter
  636. : center);
  637. center = AIR_CLAMP(nrrdCenterUnknown+1, center, nrrdCenterLast-1);
  638. return center;
  639. }
  640. int
  641. _nrrdCenter2(int center, int defCenter) {
  642. center = (nrrdCenterUnknown == center
  643. ? defCenter
  644. : center);
  645. center = AIR_CLAMP(nrrdCenterUnknown+1, center, nrrdCenterLast-1);
  646. return center;
  647. }
  648. /*
  649. ******** nrrdAxisInfoPos()
  650. **
  651. ** given a nrrd, an axis, and a (floating point) index space position,
  652. ** return the position implied the axis's min, max, and center
  653. ** Does the opposite of nrrdAxisIdx().
  654. **
  655. ** does not use biff
  656. */
  657. double
  658. nrrdAxisInfoPos(const Nrrd *nrrd, unsigned int ax, double idx) {
  659. int center;
  660. size_t size;
  661. double min, max;
  662. if (!( nrrd && ax <= nrrd->dim-1 )) {
  663. return AIR_NAN;
  664. }
  665. center = _nrrdCenter(nrrd->axis[ax].center);
  666. min = nrrd->axis[ax].min;
  667. max = nrrd->axis[ax].max;
  668. size = nrrd->axis[ax].size;
  669. return NRRD_POS(center, min, max, size, idx);
  670. }
  671. /*
  672. ******** nrrdAxisInfoIdx()
  673. **
  674. ** given a nrrd, an axis, and a (floating point) world space position,
  675. ** return the index implied the axis's min, max, and center.
  676. ** Does the opposite of nrrdAxisPos().
  677. **
  678. ** does not use biff
  679. */
  680. double
  681. nrrdAxisInfoIdx(const Nrrd *nrrd, unsigned int ax, double pos) {
  682. int center;
  683. size_t size;
  684. double min, max;
  685. if (!( nrrd && ax <= nrrd->dim-1 )) {
  686. return AIR_NAN;
  687. }
  688. center = _nrrdCenter(nrrd->axis[ax].center);
  689. min = nrrd->axis[ax].min;
  690. max = nrrd->axis[ax].max;
  691. size = nrrd->axis[ax].size;
  692. return NRRD_IDX(center, min, max, size, pos);
  693. }
  694. /*
  695. ******** nrrdAxisInfoPosRange()
  696. **
  697. ** given a nrrd, an axis, and two (floating point) index space positions,
  698. ** return the range of positions implied the axis's min, max, and center
  699. ** The opposite of nrrdAxisIdxRange()
  700. */
  701. void
  702. nrrdAxisInfoPosRange(double *loP, double *hiP,
  703. const Nrrd *nrrd, unsigned int ax,
  704. double loIdx, double hiIdx) {
  705. int center, flip = 0;
  706. size_t size;
  707. double min, max, tmp;
  708. if (!( loP && hiP && nrrd && ax <= nrrd->dim-1 )) {
  709. *loP = *hiP = AIR_NAN;
  710. return;
  711. }
  712. center = _nrrdCenter(nrrd->axis[ax].center);
  713. min = nrrd->axis[ax].min;
  714. max = nrrd->axis[ax].max;
  715. size = nrrd->axis[ax].size;
  716. if (loIdx > hiIdx) {
  717. flip = 1;
  718. tmp = loIdx; loIdx = hiIdx; hiIdx = tmp;
  719. }
  720. if (nrrdCenterCell == center) {
  721. *loP = AIR_AFFINE(0, loIdx, size, min, max);
  722. *hiP = AIR_AFFINE(0, hiIdx+1, size, min, max);
  723. } else {
  724. *loP = AIR_AFFINE(0, loIdx, size-1, min, max);
  725. *hiP = AIR_AFFINE(0, hiIdx, size-1, min, max);
  726. }
  727. if (flip) {
  728. tmp = *loP; *loP = *hiP; *hiP = tmp;
  729. }
  730. return;
  731. }
  732. /*
  733. ******** nrrdAxisInfoIdxRange()
  734. **
  735. ** given a nrrd, an axis, and two (floating point) world space positions,
  736. ** return the range of index space implied the axis's min, max, and center
  737. ** The opposite of nrrdAxisPosRange().
  738. **
  739. ** Actually- there are situations where sending an interval through
  740. ** nrrdAxisIdxRange -> nrrdAxisPosRange -> nrrdAxisIdxRange
  741. ** such as in cell centering, when the range of positions given does
  742. ** not even span one sample. Such as:
  743. ** axis->size = 4, axis->min = -4, axis->max = 4, loPos = 0, hiPos = 1
  744. ** --> nrrdAxisIdxRange == (2, 1.5) --> nrrdAxisPosRange == (2, -1)
  745. ** The basic problem is that because of the 0.5 offset inherent in
  746. ** cell centering, there are situations where (in terms of the arguments
  747. ** to nrrdAxisIdxRange()) loPos < hiPos, but *loP > *hiP.
  748. */
  749. void
  750. nrrdAxisInfoIdxRange(double *loP, double *hiP,
  751. const Nrrd *nrrd, unsigned int ax,
  752. double loPos, double hiPos) {
  753. int center, flip = 0;
  754. size_t size;
  755. double min, max, tmp;
  756. if (!( loP && hiP && nrrd && ax <= nrrd->dim-1 )) {
  757. *loP = *hiP = AIR_NAN;
  758. return;
  759. }
  760. center = _nrrdCenter(nrrd->axis[ax].center);
  761. min = nrrd->axis[ax].min;
  762. max = nrrd->axis[ax].max;
  763. size = nrrd->axis[ax].size;
  764. if (loPos > hiPos) {
  765. flip = 1;
  766. tmp = loPos; loPos = hiPos; hiPos = tmp;
  767. }
  768. if (nrrdCenterCell == center) {
  769. if (min < max) {
  770. *loP = AIR_AFFINE(min, loPos, max, 0, size);
  771. *hiP = AIR_AFFINE(min, hiPos, max, -1, size-1);
  772. } else {
  773. *loP = AIR_AFFINE(min, loPos, max, -1, size-1);
  774. *hiP = AIR_AFFINE(min, hiPos, max, 0, size);
  775. }
  776. } else {
  777. *loP = AIR_AFFINE(min, loPos, max, 0, size-1);
  778. *hiP = AIR_AFFINE(min, hiPos, max, 0, size-1);
  779. }
  780. if (flip) {
  781. tmp = *loP; *loP = *hiP; *hiP = tmp;
  782. }
  783. return;
  784. }
  785. void
  786. nrrdAxisInfoSpacingSet(Nrrd *nrrd, unsigned int ax) {
  787. int sign;
  788. double min, max, tmp;
  789. if (!( nrrd && ax <= nrrd->dim-1 )) {
  790. return;
  791. }
  792. min = nrrd->axis[ax].min;
  793. max = nrrd->axis[ax].max;
  794. if (!( AIR_EXISTS(min) && AIR_EXISTS(max) )) {
  795. /* there's no actual basis on which to set the spacing information,
  796. but we have to set it something, so here goes .. */
  797. nrrd->axis[ax].spacing = nrrdDefaultSpacing;
  798. return;
  799. }
  800. if (min > max) {
  801. tmp = min; min = max; max = tmp;
  802. sign = -1;
  803. } else {
  804. sign = 1;
  805. }
  806. /* the skinny */
  807. nrrd->axis[ax].spacing = NRRD_SPACING(_nrrdCenter(nrrd->axis[ax].center),
  808. min, max, nrrd->axis[ax].size);
  809. nrrd->axis[ax].spacing *= sign;
  810. return;
  811. }
  812. void
  813. nrrdAxisInfoMinMaxSet(Nrrd *nrrd, unsigned int ax, int defCenter) {
  814. int center;
  815. double spacing;
  816. if (!( nrrd && ax <= nrrd->dim-1 )) {
  817. return;
  818. }
  819. center = _nrrdCenter2(nrrd->axis[ax].center, defCenter);
  820. spacing = nrrd->axis[ax].spacing;
  821. if (!AIR_EXISTS(spacing))
  822. spacing = nrrdDefaultSpacing;
  823. if (nrrdCenterCell == center) {
  824. nrrd->axis[ax].min = 0;
  825. nrrd->axis[ax].max = spacing*nrrd->axis[ax].size;
  826. } else {
  827. nrrd->axis[ax].min = 0;
  828. nrrd->axis[ax].max = spacing*(nrrd->axis[ax].size - 1);
  829. }
  830. return;
  831. }
  832. /*
  833. ******** nrrdDomainAxesGet
  834. **
  835. ** Based on the per-axis "kind" field, learns which are the domain
  836. ** (resample-able) axes of an image, in other words, the axes which
  837. ** correspond to independent variables. The return value is the
  838. ** number of domain axes, and that many values are set in the given
  839. ** axisIdx[] array
  840. **
  841. ** NOTE: this takes a wild guess that an unset (nrrdKindUnknown) kind
  842. ** is a domain axis.
  843. */
  844. unsigned int
  845. nrrdDomainAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX]) {
  846. unsigned int domAxi, axi;
  847. if (!( nrrd && axisIdx )) {
  848. return 0;
  849. }
  850. domAxi = 0;
  851. for (axi=0; axi<nrrd->dim; axi++) {
  852. if (nrrdKindUnknown == nrrd->axis[axi].kind
  853. || nrrdKindIsDomain(nrrd->axis[axi].kind)) {
  854. axisIdx[domAxi++] = axi;
  855. }
  856. }
  857. return domAxi;
  858. }
  859. int
  860. _nrrdSpaceVecExists(const Nrrd *nrrd, unsigned int axi) {
  861. unsigned int sai;
  862. int ret;
  863. if (!( nrrd && axi < nrrd->dim && nrrd->spaceDim )) {
  864. ret = AIR_FALSE;
  865. } else {
  866. ret = AIR_TRUE;
  867. for (sai=0; sai<nrrd->spaceDim; sai++) {
  868. ret &= AIR_EXISTS(nrrd->axis[axi].spaceDirection[sai]);
  869. }
  870. }
  871. return ret;
  872. }
  873. unsigned int
  874. nrrdSpatialAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX]) {
  875. unsigned int spcAxi, axi;
  876. if (!( nrrd && axisIdx && nrrd->spaceDim)) {
  877. return 0;
  878. }
  879. spcAxi = 0;
  880. for (axi=0; axi<nrrd->dim; axi++) {
  881. if (_nrrdSpaceVecExists(nrrd, axi)) {
  882. axisIdx[spcAxi++] = axi;
  883. }
  884. }
  885. return spcAxi;
  886. }
  887. /*
  888. ******** nrrdRangeAxesGet
  889. **
  890. ** Based on the per-axis "kind" field, learns which are the range
  891. ** (non-resample-able) axes of an image, in other words, the axes
  892. ** which correspond to dependent variables. The return value is the
  893. ** number of range axes; that number of values are set in the given
  894. ** axisIdx[] array
  895. **
  896. ** Note: this really is as simple as returning the complement of the
  897. ** axis selected by nrrdDomainAxesGet()
  898. */
  899. unsigned int
  900. nrrdRangeAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX]) {
  901. unsigned int domNum, domIdx[NRRD_DIM_MAX], rngAxi, axi, ii, isDom;
  902. if (!( nrrd && axisIdx )) {
  903. return 0;
  904. }
  905. domNum = nrrdDomainAxesGet(nrrd, domIdx);
  906. rngAxi = 0;
  907. for (axi=0; axi<nrrd->dim; axi++) {
  908. isDom = AIR_FALSE;
  909. for (ii=0; ii<domNum; ii++) { /* yes, inefficient */
  910. isDom |= axi == domIdx[ii];
  911. }
  912. if (!isDom) {
  913. axisIdx[rngAxi++] = axi;
  914. }
  915. }
  916. return rngAxi;
  917. }
  918. unsigned int
  919. nrrdNonSpatialAxesGet(const Nrrd *nrrd, unsigned int axisIdx[NRRD_DIM_MAX]) {
  920. unsigned int spcNum, spcIdx[NRRD_DIM_MAX], nspAxi, axi, ii, isSpc;
  921. if (!( nrrd && axisIdx )) {
  922. return 0;
  923. }
  924. /* HEY: copy and paste, should refactor with above */
  925. spcNum = nrrdSpatialAxesGet(nrrd, spcIdx);
  926. nspAxi = 0;
  927. for (axi=0; axi<nrrd->dim; axi++) {
  928. isSpc = AIR_FALSE;
  929. for (ii=0; ii<spcNum; ii++) { /* yes, inefficient */
  930. isSpc |= axi == spcIdx[ii];
  931. }
  932. if (!isSpc) {
  933. axisIdx[nspAxi++] = axi;
  934. }
  935. }
  936. return nspAxi;
  937. }
  938. /*
  939. ******** nrrdSpacingCalculate
  940. **
  941. ** Determine nrrdSpacingStatus, and whatever can be calculated about
  942. ** spacing for a given axis. Takes a nrrd, an axis, a double pointer
  943. ** (for returning a scalar), a space vector, and an int pointer for
  944. ** returning the known length of the space vector.
  945. **
  946. ** The behavior of what has been set by the function is determined by
  947. ** the return value, which takes values from the nrrdSpacingStatus*
  948. ** enum, as follows:
  949. **
  950. ** returned status value: what it means, and what it set
  951. ** ---------------------------------------------------------------------------
  952. ** nrrdSpacingStatusUnknown Something about the given arguments is
  953. ** invalid.
  954. ** *spacing = NaN,
  955. ** vector = all NaNs
  956. **
  957. ** nrrdSpacingStatusNone There is no spacing info at all:
  958. ** *spacing = NaN,
  959. ** vector = all NaNs
  960. **
  961. ** nrrdSpacingStatusScalarNoSpace There is no surrounding space, but the
  962. ** axis's spacing was known.
  963. ** *spacing = axis->spacing,
  964. ** vector = all NaNs
  965. **
  966. ** nrrdSpacingStatusScalarWithSpace There *is* a surrounding space, but the
  967. ** given axis does not live in that space,
  968. ** because it has no space direction. Caller
  969. ** may want to think about what's going on.
  970. ** *spacing = axis->spacing,
  971. ** vector = all NaNs
  972. **
  973. ** nrrdSpacingStatusDirection There is a surrounding space, in which
  974. ** this axis has a direction V:
  975. ** *spacing = |V| (length of direction),
  976. ** vector = V/|V| (normalized direction)
  977. ** NOTE: it is still possible for both
  978. ** *spacing and vector to be all NaNs!!
  979. */
  980. int
  981. nrrdSpacingCalculate(const Nrrd *nrrd, unsigned int ax,
  982. double *spacing, double vector[NRRD_SPACE_DIM_MAX]) {
  983. int ret;
  984. if (!( nrrd && spacing && vector
  985. && ax <= nrrd->dim-1
  986. && !_nrrdCheck(nrrd, AIR_FALSE, AIR_FALSE) )) {
  987. /* there's a problem with the arguments. Note: the _nrrdCheck()
  988. call does not check on non-NULL-ity of nrrd->data */
  989. ret = nrrdSpacingStatusUnknown;
  990. if (spacing) {
  991. *spacing = AIR_NAN;
  992. }
  993. if (vector) {
  994. nrrdSpaceVecSetNaN(vector);
  995. }
  996. } else {
  997. if (AIR_EXISTS(nrrd->axis[ax].spacing)) {
  998. if (nrrd->spaceDim > 0) {
  999. ret = nrrdSpacingStatusScalarWithSpace;
  1000. } else {
  1001. ret = nrrdSpacingStatusScalarNoSpace;
  1002. }
  1003. *spacing = nrrd->axis[ax].spacing;
  1004. nrrdSpaceVecSetNaN(vector);
  1005. } else {
  1006. if (nrrd->spaceDim > 0 && _nrrdSpaceVecExists(nrrd, ax)) {
  1007. ret = nrrdSpacingStatusDirection;
  1008. *spacing = nrrdSpaceVecNorm(nrrd->spaceDim,
  1009. nrrd->axis[ax].spaceDirection);
  1010. nrrdSpaceVecScale(vector, 1.0/(*spacing),
  1011. nrrd->axis[ax].spaceDirection);
  1012. } else {
  1013. ret = nrrdSpacingStatusNone;
  1014. *spacing = AIR_NAN;
  1015. nrrdSpaceVecSetNaN(vector);
  1016. }
  1017. }
  1018. }
  1019. return ret;
  1020. }
  1021. int
  1022. nrrdOrientationReduce(Nrrd *nout, const Nrrd *nin,
  1023. int setMinsFromOrigin) {
  1024. static const char me[]="nrrdOrientationReduce";
  1025. unsigned int spatialAxisNum, spatialAxisIdx[NRRD_DIM_MAX], saxii;
  1026. NrrdAxisInfo *axis;
  1027. if (!(nout && nin)) {
  1028. biffAddf(NRRD, "%s: got NULL spacing", me);
  1029. return 1;
  1030. }
  1031. if (nout != nin) {
  1032. if (nrrdCopy(nout, nin)) {
  1033. biffAddf(NRRD, "%s: trouble doing initial copying", me);
  1034. return 1;
  1035. }
  1036. }
  1037. if (!nout->spaceDim) {
  1038. /* we're done! */
  1039. return 0;
  1040. }
  1041. spatialAxisNum = nrrdSpatialAxesGet(nout, spatialAxisIdx);
  1042. for (saxii=0; saxii<spatialAxisNum; saxii++) {
  1043. axis = nout->axis + spatialAxisIdx[saxii];
  1044. axis->spacing = nrrdSpaceVecNorm(nout->spaceDim,
  1045. axis->spaceDirection);
  1046. if (setMinsFromOrigin) {
  1047. axis->min = (saxii < nout->spaceDim
  1048. ? nout->spaceOrigin[saxii]
  1049. : AIR_NAN);
  1050. }
  1051. }
  1052. nrrdSpaceSet(nout, nrrdSpaceUnknown);
  1053. return 0;
  1054. }