11 |
*/ |
*/ |
12 |
|
|
13 |
#include "Diderot/diderot.h" |
#include "Diderot/diderot.h" |
14 |
|
#include <teem/nrrd.h> |
15 |
|
|
16 |
// compute the address of the i'th element in the sequence |
// compute the address of the i'th element in the sequence |
17 |
STATIC_INLINE void* ElemAddr(void *base, size_t elemSz, unsigned int i) |
STATIC_INLINE void* ElemAddr(void *base, size_t elemSz, unsigned int i) |
67 |
return (void *)((char *)dst + cpySz); |
return (void *)((char *)dst + cpySz); |
68 |
} |
} |
69 |
} |
} |
70 |
|
|
71 |
|
static struct { |
72 |
|
bool isFloat; |
73 |
|
unsigned int sizeb; |
74 |
|
} NrrdTypeInfo[nrrdTypeLast] = { |
75 |
|
[nrrdTypeDefault] = {false, 0}, /* 0: signifies "determine output type for me" */ |
76 |
|
[nrrdTypeChar] = {false, 1}, /* 1: signed 1-byte integer */ |
77 |
|
[nrrdTypeUChar] = {false, 1}, /* 2: unsigned 1-byte integer */ |
78 |
|
[nrrdTypeShort] = {false, 2}, /* 3: signed 2-byte integer */ |
79 |
|
[nrrdTypeUShort] = {false, 2}, /* 4: unsigned 2-byte integer */ |
80 |
|
[nrrdTypeInt] = {false, 4}, /* 5: signed 4-byte integer */ |
81 |
|
[nrrdTypeUInt] = {false, 4}, /* 6: unsigned 4-byte integer */ |
82 |
|
[nrrdTypeLLong] = {false, 8}, /* 7: signed 8-byte integer */ |
83 |
|
[nrrdTypeULLong] = {false, 8}, /* 8: unsigned 8-byte integer */ |
84 |
|
[nrrdTypeFloat] = {true, 4}, /* 9: 4-byte floating point */ |
85 |
|
[nrrdTypeDouble] = {true, 8}, /* 10: 8-byte floating point */ |
86 |
|
[nrrdTypeBlock] = {false, 0}, /* 11: size user defined at run time; MUST BE LAST */ |
87 |
|
}; |
88 |
|
|
89 |
|
//! Check that a nrrd has the expected structure for loading into a dynamic sequence |
90 |
|
//! \param wrld the world; used to report errors |
91 |
|
//! \param nin the nrrd to check |
92 |
|
//! \param nDims the number of dimensions in the sequence elements |
93 |
|
//! \param dims the array of sequence element dimensions |
94 |
|
//! \return the number of values per element, or zero on error |
95 |
|
static unsigned int CheckNrrd ( |
96 |
|
WorldPrefix_t *wrld, |
97 |
|
Nrrd *nin, |
98 |
|
unsigned int nDims, |
99 |
|
unsigned int *dims) |
100 |
|
{ |
101 |
|
|
102 |
|
// compute the expected number of values per sequence element |
103 |
|
unsigned int nValuesPerElem = 1; |
104 |
|
for (unsigned int i = 0; i < nDims; i++) { |
105 |
|
nValuesPerElem *= dims[i]; |
106 |
|
} |
107 |
|
|
108 |
|
// check the structure of the nrrd file |
109 |
|
if (nin->spaceDim != 1) { |
110 |
|
Diderot_Error (wrld, "unexpected number of axes in nrrd; expected 1, found %d\n", |
111 |
|
nin->spaceDim); |
112 |
|
return 0; |
113 |
|
} |
114 |
|
if (nin->dim - 1 != nDims) { |
115 |
|
Diderot_Error (wrld, "unexpected nrrd dimension; expected %d, found %d\n", |
116 |
|
nDims, nin->dim-1); |
117 |
|
return 0; |
118 |
|
} |
119 |
|
for (unsigned int i = 0; i < nDims; i++) { |
120 |
|
if (dims[i] != nin->axis[i+1].size) { |
121 |
|
Diderot_Error (wrld, "nrrd shape does not match expected structure\n"); |
122 |
|
return 0; |
123 |
|
} |
124 |
|
} |
125 |
|
if (NrrdTypeInfo[nin->type].size == 0) { |
126 |
|
Diderot_Error (wrld, "bogus element type %d in nrrd\n", nin->type); |
127 |
|
return 0; |
128 |
|
} |
129 |
|
|
130 |
|
return nValuesPerElem; |
131 |
|
} |
132 |
|
|
133 |
|
//! load a dynamic sequence from a Nrrd file, where the sequence elements have real ground type. |
134 |
|
//! \param wrld the world; used to report errors |
135 |
|
//! \param nin the nrrd to check |
136 |
|
//! \param nDims the number of dimensions in the sequence elements |
137 |
|
//! \param dims the array of sequence element dimensions |
138 |
|
//! \return the dynamic sequence, or zero on error |
139 |
|
Diderot_DynSeq_t *Diderot_DynSeqLoadReal ( |
140 |
|
WorldPrefix_t *wrld, |
141 |
|
Nrrd *nin, |
142 |
|
unsigned int nDims, |
143 |
|
unsigned int *dims) |
144 |
|
{ |
145 |
|
unsigned int nValuesPerElem = CheckNrrd(wrld, nin, nDims, dims); |
146 |
|
size_t elemSz = SIZEOF_DIDEROT_REAL * nValuesPerElem; |
147 |
|
|
148 |
|
if (nValuesPerElem == 0) |
149 |
|
return (Diderot_DynSeq_t *)0; |
150 |
|
|
151 |
|
// get the number of elements |
152 |
|
size_t nElems = nin->axis[0].size; |
153 |
|
|
154 |
|
// allocate the dynamic sequence |
155 |
|
Diderot_DynSeq_t *seq = Diderot_DynSeqAlloc(elemSz, nElems); |
156 |
|
|
157 |
|
// initialize the sequence from the nrrd |
158 |
|
if (! nrrdTypeInfo[nin->type].isFloat || (nrrdTypeInfo[nin->type].size != SIZEOF_DIDEROT_REAL)) { |
159 |
|
// this is the slow path; we have to convert values as they are copied from the nrrd |
160 |
|
#if defined(DIDEROT_DOUBLE_PRECISION) |
161 |
|
double (*loadFn)(const void *) = nrrdDLoad[nin->type]; |
162 |
|
#else |
163 |
|
float (*loadFn)(const void *) = nrrdFLoad[nin->type]; |
164 |
|
#endif |
165 |
|
Diderot_real_t *dst = (Diderot_real_t *)seq->data; |
166 |
|
char *src = (char *)nin->data; |
167 |
|
size_t srcElemSz = NrrdTypeInfo[nin->type].size; |
168 |
|
for (size_t i = 0; i < nElems * nValuesPerElem; i++) { |
169 |
|
*dst++ = loadFn(src); |
170 |
|
src += srcElemSz; |
171 |
|
} |
172 |
|
} |
173 |
|
else { |
174 |
|
// this is the fast path, where we can just do a bulk memcpy |
175 |
|
memcpy (seq->data, nin->data, nElems * elemSz); |
176 |
|
} |
177 |
|
|
178 |
|
return seq; |
179 |
|
|
180 |
|
} |
181 |
|
|
182 |
|
|
183 |
|
//! load a dynamic sequence from a Nrrd file, where the sequence elements have int ground type. |
184 |
|
//! \param wrld the world; used to report errors |
185 |
|
//! \param nin the nrrd to check |
186 |
|
//! \param nDims the number of dimensions in the sequence elements |
187 |
|
//! \param dims the array of sequence element dimensions |
188 |
|
//! \return the dynamic sequence, or zero on error |
189 |
|
Diderot_DynSeq_t *Diderot_DynSeqLoadInt ( |
190 |
|
WorldPrefix_t *wrld, |
191 |
|
Nrrd *nin, |
192 |
|
unsigned int nDims, |
193 |
|
unsigned int *dims) |
194 |
|
{ |
195 |
|
unsigned int nValuesPerElem = CheckNrrd(wrld, nin, nDims, dims); |
196 |
|
size_t elemSz = SIZEOF_DIDEROT_INT * nValuesPerElem; |
197 |
|
|
198 |
|
if (nValuesPerElem == 0) |
199 |
|
return (Diderot_DynSeq_t *)0; |
200 |
|
|
201 |
|
if (nrrdTypeInfo[nin->type].isFloat) { |
202 |
|
Diderot_Error (wrld, "expected integer element type for int sequence, but found %d\n", nin->type); |
203 |
|
return 0; |
204 |
|
} |
205 |
|
|
206 |
|
// get the number of elements |
207 |
|
size_t nElems = nin->axis[0].size; |
208 |
|
|
209 |
|
// allocate the dynamic sequence |
210 |
|
Diderot_DynSeq_t *seq = Diderot_DynSeqAlloc(elemSz, nElems); |
211 |
|
|
212 |
|
// initialize the sequence from the nrrd |
213 |
|
if (nrrdTypeInfo[nin->type].size != SIZEOF_DIDEROT_INT) { |
214 |
|
// this is the slow path; we have to convert values as they are copied from the nrrd |
215 |
|
int (*loadFn)(const void *) = nrrdILoad[nin->type]; |
216 |
|
Diderot_int_t *dst = (Diderot_int_t *)seq->data; |
217 |
|
char *src = (char *)nin->data; |
218 |
|
size_t srcElemSz = NrrdTypeInfo[nin->type].size; |
219 |
|
for (size_t i = 0; i < nElems * nValuesPerElem; i++) { |
220 |
|
*dst++ = loadFn(src); |
221 |
|
src += srcElemSz; |
222 |
|
} |
223 |
|
} |
224 |
|
else { |
225 |
|
// this is the fast path, where we can just do a bulk memcpy |
226 |
|
memcpy (seq->data, nin->data, nElems * elemSz); |
227 |
|
} |
228 |
|
|
229 |
|
return seq; |
230 |
|
|
231 |
|
} |
232 |
|
|
233 |
|
|
234 |
|
//! load a dynamic sequence from a Nrrd file, where the sequence elements have bool ground type. |
235 |
|
//! \param wrld the world; used to report errors |
236 |
|
//! \param nin the nrrd to check |
237 |
|
//! \param nDims the number of dimensions in the sequence elements |
238 |
|
//! \param dims the array of sequence element dimensions |
239 |
|
//! \return the dynamic sequence, or zero on error |
240 |
|
Diderot_DynSeq_t *Diderot_DynSeqLoadBool ( |
241 |
|
WorldPrefix_t *wrld, |
242 |
|
Nrrd *nin, |
243 |
|
unsigned int nDims, |
244 |
|
unsigned int *dims) |
245 |
|
{ |
246 |
|
unsigned int nValuesPerElem = CheckNrrd(wrld, nin, nDims, dims); |
247 |
|
size_t elemSz = SIZEOF_DIDEROT_BOOL * nValuesPerElem; |
248 |
|
|
249 |
|
if (nValuesPerElem == 0) |
250 |
|
return (Diderot_DynSeq_t *)0; |
251 |
|
|
252 |
|
if (nrrdTypeInfo[nin->type].isFloat) { |
253 |
|
Diderot_Error (wrld, "expected integer element type for bool sequence, but found %d\n", nin->type); |
254 |
|
return 0; |
255 |
|
} |
256 |
|
|
257 |
|
// get the number of elements |
258 |
|
size_t nElems = nin->axis[0].size; |
259 |
|
|
260 |
|
// allocate the dynamic sequence |
261 |
|
Diderot_DynSeq_t *seq = Diderot_DynSeqAlloc(elemSz, nElems); |
262 |
|
|
263 |
|
// initialize the sequence from the nrrd |
264 |
|
if (nrrdTypeInfo[nin->type].size != sizeof(bool)) { |
265 |
|
// this is the slow path; we have to convert values as they are copied from the nrrd |
266 |
|
int (*loadFn)(const void *) = nrrdILoad[nin->type]; |
267 |
|
bool *dst = (bool *)seq->data; |
268 |
|
char *src = (char *)nin->data; |
269 |
|
size_t srcElemSz = NrrdTypeInfo[nin->type].size; |
270 |
|
for (size_t i = 0; i < nElems * nValuesPerElem; i++) { |
271 |
|
*dst++ = loadFn(src) ? true : false; |
272 |
|
src += srcElemSz; |
273 |
|
} |
274 |
|
} |
275 |
|
else { |
276 |
|
// this is the fast path, where we can just do a bulk memcpy |
277 |
|
memcpy (seq->data, nin->data, nElems * elemSz); |
278 |
|
} |
279 |
|
|
280 |
|
return seq; |
281 |
|
|
282 |
|
} |