36 #include <cxmessages.h>
37 #include <cxstrutils.h>
39 #include <cpl_error.h>
40 #include <cpl_array.h>
41 #include <cpl_matrix.h>
42 #include <cpl_image.h>
43 #include <cpl_imagelist.h>
44 #include <cpl_propertylist.h>
67 typedef enum GiCubeAxes GiCubeAxes;
75 typedef struct GiCubeAxis GiCubeAxis;
79 cxdouble origin[GICUBE_AXES];
80 cxdouble point[GICUBE_AXES];
82 cxchar* axis_type[GICUBE_AXES];
83 cxchar* axis_unit[GICUBE_AXES];
85 cpl_matrix* transform;
88 typedef struct GiCubeWCS GiCubeWCS;
97 GiCubeAxis* axes[GICUBE_AXES];
103 cpl_imagelist* planes;
109 _giraffe_cube_clear_wcs(GiCube*
self)
112 register cxsize axis = 0;
114 for (axis = 0; axis < GICUBE_AXES; ++axis) {
116 if (self->wcs->axis_type[axis] != NULL) {
117 cx_free(self->wcs->axis_type[axis]);
118 self->wcs->axis_type[axis] = NULL;
121 if (self->wcs->axis_unit[axis] != NULL) {
122 cx_free(self->wcs->axis_unit[axis]);
123 self->wcs->axis_unit[axis] = NULL;
128 cpl_matrix_delete(self->wcs->transform);
129 self->wcs->transform = NULL;
140 _giraffe_cube_set_wcs(GiCube*
self,
const cpl_propertylist* axes,
141 const cpl_matrix* transform)
144 GiCubeWCS* wcs = NULL;
146 cx_assert(
self != NULL);
147 cx_assert(axes != NULL);
148 cx_assert(transform != NULL);
150 wcs = cx_malloc(
sizeof *self->wcs);
152 wcs->transform = cpl_matrix_duplicate(transform);
154 wcs->origin[GICUBE_X] = cpl_propertylist_get_double(axes,
"XORIGIN");
155 wcs->origin[GICUBE_Y] = cpl_propertylist_get_double(axes,
"YORIGIN");
156 wcs->origin[GICUBE_Z] = cpl_propertylist_get_double(axes,
"ZORIGIN");
158 wcs->point[GICUBE_X] = cpl_propertylist_get_double(axes,
"XPOINT");
159 wcs->point[GICUBE_Y] = cpl_propertylist_get_double(axes,
"YPOINT");
160 wcs->point[GICUBE_Z] = cpl_propertylist_get_double(axes,
"ZPOINT");
162 wcs->axis_type[GICUBE_X] =
163 cx_strdup(cpl_propertylist_get_string(axes,
"XTYPE"));
164 wcs->axis_type[GICUBE_Y] =
165 cx_strdup(cpl_propertylist_get_string(axes,
"YTYPE"));
166 wcs->axis_type[GICUBE_Z] =
167 cx_strdup(cpl_propertylist_get_string(axes,
"ZTYPE"));
169 wcs->axis_unit[GICUBE_X] =
170 cx_strdup(cpl_propertylist_get_string(axes,
"XUNIT"));
171 wcs->axis_unit[GICUBE_Y] =
172 cx_strdup(cpl_propertylist_get_string(axes,
"YUNIT"));
173 wcs->axis_unit[GICUBE_Z] =
174 cx_strdup(cpl_propertylist_get_string(axes,
"ZUNIT"));
177 if (self->wcs != NULL) {
178 _giraffe_cube_clear_wcs(
self);
188 inline static cxdouble
189 _giraffe_cube_get_wcs_origin(
const GiCube*
self, GiCubeAxes axis)
191 return self->wcs->origin[axis];
195 inline static cxdouble
196 _giraffe_cube_get_wcs_point(
const GiCube*
self, GiCubeAxes axis)
198 return self->wcs->point[axis];
202 inline static const cxchar*
203 _giraffe_cube_get_wcs_axistype(
const GiCube*
self, GiCubeAxes axis)
205 return self->wcs->axis_type[axis];
209 inline static const cxchar*
210 _giraffe_cube_get_wcs_axisunit(
const GiCube*
self, GiCubeAxes axis)
212 return self->wcs->axis_unit[axis];
216 inline static const cpl_matrix*
217 _giraffe_cube_get_wcs_transform(
const GiCube*
self)
219 return self->wcs->transform;
224 _giraffe_cube_set_size(GiCube*
self, cxsize width, cxsize height,
229 self->height = height;
232 self->size =
self->width *
self->height *
self->depth;
239 inline static GiCube*
240 _giraffe_cube_new(
void)
243 GiCube*
self = cx_malloc(
sizeof *
self);
247 _giraffe_cube_set_size(
self, 0, 0, 0);
249 self->axes[GICUBE_X] = NULL;
250 self->axes[GICUBE_Y] = NULL;
251 self->axes[GICUBE_Z] = NULL;
265 _giraffe_cube_init_planes(GiCube*
self)
268 register cxsize i = 0;
270 register cxdouble* base = NULL;
273 self->planes = cpl_imagelist_new();
274 cx_assert(self->planes != NULL);
279 for (i = 0; i <
self->depth; i++) {
281 cpl_image* plane = cpl_image_wrap_double(self->width, self->height,
284 cx_assert(plane != NULL);
285 cpl_imagelist_set(self->planes, plane, i);
287 base +=
self->width *
self->height;
297 _giraffe_cube_clear_planes(GiCube*
self)
300 register cxsize i = 0;
303 for (i = 0; i <
self->depth; i++) {
305 cpl_image* plane = cpl_imagelist_unset(self->planes, 0);
307 cpl_image_unwrap(plane);
311 cx_assert(cpl_imagelist_get_size(self->planes) == 0);
313 cpl_imagelist_delete(self->planes);
322 _giraffe_cube_delete(GiCube*
self)
325 register cxint i = 0;
327 for (i = 0; i < GICUBE_AXES; i++) {
328 if (self->axes[i] != NULL) {
329 cx_free(self->axes[i]);
330 self->axes[i] = NULL;
334 if (self->wcs != NULL) {
335 _giraffe_cube_clear_wcs(
self);
339 if (self->planes != NULL) {
340 _giraffe_cube_clear_planes(
self);
344 if (self->pixels != NULL) {
345 cx_free(self->pixels);
357 _giraffe_cube_has_axis(
const GiCube*
self, GiCubeAxes axis)
359 return (self->axes[axis] == NULL) ? FALSE : TRUE;
364 _giraffe_cube_get_axis(
const GiCube*
self, GiCubeAxes axis, cxdouble* start,
368 if (self->axes[axis] == NULL) {
374 *start =
self->axes[axis]->start;
378 *step =
self->axes[axis]->step;
389 _giraffe_cube_set_axis(GiCube*
self, GiCubeAxes axis, cxdouble start,
393 if (self->axes[axis] == NULL) {
394 self->axes[axis] = cx_calloc(1,
sizeof(GiCubeAxis));
397 cx_assert(self->axes[axis] != NULL);
399 self->axes[axis]->start = start;
400 self->axes[axis]->step = step;
423 return _giraffe_cube_new();
458 GiCube*
self = _giraffe_cube_new();
461 _giraffe_cube_set_size(
self, width, height, depth);
463 if (self->size == 0) {
464 _giraffe_cube_delete(
self);
472 self->pixels = cx_calloc(self->size,
sizeof(cxdouble));
475 cx_assert(self->pixels != NULL);
483 giraffe_error_push();
485 _giraffe_cube_init_planes(
self);
487 if (cpl_error_get_code() != CPL_ERROR_NONE) {
488 _giraffe_cube_delete(
self);
516 _giraffe_cube_delete(
self);
541 cx_assert(
self != NULL);
564 cx_assert(
self != NULL);
587 cx_assert(
self != NULL);
610 cx_assert(
self != NULL);
638 const cxchar*
const _id =
"giraffe_cube_set_size";
641 cx_assert(
self != NULL);
643 if ((width == 0) || (height == 0) || (depth == 0)) {
644 cpl_error_set(_id, CPL_ERROR_ILLEGAL_INPUT);
648 if ((self->width == width) && (self->height == height) &&
649 (self->depth == depth)) {
650 memset(self->pixels, 0, self->size *
sizeof(cxdouble));
658 if (self->planes != NULL) {
659 _giraffe_cube_clear_planes(
self);
662 if (self->pixels != NULL) {
663 cx_free(self->pixels);
671 _giraffe_cube_set_size(
self, width, height, depth);
679 self->pixels = cx_calloc(self->size,
sizeof(cxdouble));
680 cx_assert(self->pixels);
683 giraffe_error_push();
685 _giraffe_cube_init_planes(
self);
687 if (cpl_error_get_code() != CPL_ERROR_NONE) {
718 const cxchar*
const _id =
"giraffe_cube_get_data";
722 cpl_error_set(_id, CPL_ERROR_NULL_INPUT);
748 return _giraffe_cube_has_axis(
self, GICUBE_X);
769 return _giraffe_cube_has_axis(
self, GICUBE_Y);
790 return _giraffe_cube_has_axis(
self, GICUBE_Z);
811 return self->wcs != NULL;
839 cx_assert(
self != NULL);
841 return _giraffe_cube_get_axis(
self, GICUBE_X, start, step);
870 cx_assert(
self != NULL);
872 return _giraffe_cube_get_axis(
self, GICUBE_Y, start, step);
901 cx_assert(
self != NULL);
903 return _giraffe_cube_get_axis(
self, GICUBE_Z, start, step);
927 cx_assert(
self != NULL);
929 return _giraffe_cube_set_axis(
self, GICUBE_X, start, step);
953 cx_assert(
self != NULL);
955 return _giraffe_cube_set_axis(
self, GICUBE_Y, start, step);
979 cx_assert(
self != NULL);
981 return _giraffe_cube_set_axis(
self, GICUBE_Z, start, step);
1004 if (self->wcs != NULL) {
1005 _giraffe_cube_clear_wcs(
self);
1041 const cpl_matrix* transformation)
1044 cx_assert(
self != NULL);
1046 if ((axes == NULL) || (transformation == NULL)) {
1050 if ((cpl_matrix_get_nrow(transformation) != GICUBE_AXES) ||
1051 (cpl_matrix_get_ncol(transformation) != GICUBE_AXES)) {
1055 if ((cpl_propertylist_has(axes,
"XORIGIN") == FALSE) ||
1056 (cpl_propertylist_has(axes,
"YORIGIN") == FALSE) ||
1057 (cpl_propertylist_has(axes,
"ZORIGIN") == FALSE)) {
1061 if ((cpl_propertylist_has(axes,
"XPOINT") == FALSE) ||
1062 (cpl_propertylist_has(axes,
"YPOINT") == FALSE) ||
1063 (cpl_propertylist_has(axes,
"ZPOINT") == FALSE)) {
1067 if ((cpl_propertylist_has(axes,
"XTYPE") == FALSE) ||
1068 (cpl_propertylist_has(axes,
"YTYPE") == FALSE) ||
1069 (cpl_propertylist_has(axes,
"ZTYPE") == FALSE)) {
1073 if ((cpl_propertylist_has(axes,
"XUNIT") == FALSE) ||
1074 (cpl_propertylist_has(axes,
"YUNIT") == FALSE) ||
1075 (cpl_propertylist_has(axes,
"ZUNIT") == FALSE)) {
1079 _giraffe_cube_set_wcs(
self, axes, transformation);
1102 cpl_error_code status = CPL_ERROR_NONE;
1109 cx_assert(self->planes != NULL);
1111 status = cpl_imagelist_power(self->planes, 0.5);
1113 if (status != CPL_ERROR_NONE) {
1154 cxsize first = (cxsize)ceil(start);
1155 cxsize last = (cxsize)floor(end);
1157 cpl_image* image = NULL;
1166 if ((start >= end) || (start < 0.) || (end > depth)) {
1171 image = cpl_image_duplicate(cpl_imagelist_get(self->planes, first));
1173 if (image != NULL) {
1175 if (first == last) {
1176 cpl_image_multiply_scalar(image, (end - start));
1182 cxdouble fstart = first - start;
1183 cxdouble fend = end - last;
1186 for (i = first + 1; i < last; ++i) {
1187 cpl_image_add(image,
1188 cpl_imagelist_get_const(self->planes, i));
1197 if ((fstart > 0.) && (first > 0)) {
1198 cpl_image* tmp = cpl_imagelist_get(self->planes, first - 1);
1200 tmp = cpl_image_multiply_scalar_create(tmp, fstart);
1201 cpl_image_add(image, tmp);
1203 cpl_image_delete(tmp);
1207 if ((fend > 0.) && (last < depth)) {
1208 cpl_image* tmp = cpl_imagelist_get(self->planes, last);
1210 tmp = cpl_image_multiply_scalar_create(tmp, fend);
1211 cpl_image_add(image, tmp);
1213 cpl_image_delete(tmp);
1245 const cxchar* filename, cxcptr data)
1248 cxbool xaxis = FALSE;
1249 cxbool yaxis = FALSE;
1250 cxbool zaxis = FALSE;
1252 cxdouble xstart = 0.;
1253 cxdouble xstep = 0.;
1254 cxdouble ystart = 0.;
1255 cxdouble ystep = 0.;
1256 cxdouble zstart = 0.;
1257 cxdouble zstep = 0.;
1259 cxuint iomode = CPL_IO_CREATE;
1262 if (properties == NULL || filename == NULL) {
1272 iomode = *((cxuint*)data);
1285 if (iomode != CPL_IO_CREATE) {
1289 giraffe_error_push();
1291 cpl_propertylist_erase_regexp(properties,
"CRVAL[0-9]*", 0);
1292 cpl_propertylist_erase_regexp(properties,
"CRPIX[0-9]*", 0);
1293 cpl_propertylist_erase_regexp(properties,
"CDELT[0-9]*", 0);
1294 cpl_propertylist_erase_regexp(properties,
"CTYPE[0-9]*", 0);
1295 cpl_propertylist_erase_regexp(properties,
"CUNIT[0-9]*", 0);
1297 cpl_propertylist_erase(properties, GIALIAS_BUNIT);
1299 cpl_propertylist_erase(properties,
"DATAMIN");
1300 cpl_propertylist_erase(properties,
"DATAMAX");
1302 cpl_propertylist_erase(properties, GIALIAS_DATAMEAN);
1303 cpl_propertylist_erase(properties, GIALIAS_DATAMEDI);
1304 cpl_propertylist_erase(properties, GIALIAS_DATASIG);
1306 cpl_propertylist_save(properties, filename, iomode);
1308 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1312 giraffe_error_pop();
1319 const cpl_array* pixels = NULL;
1346 const cxchar* ctype[GICUBE_AXES];
1347 const cxchar* cunit[GICUBE_AXES];
1351 cxdouble crpix[GICUBE_AXES];
1352 cxdouble crval[GICUBE_AXES];
1354 const cpl_matrix* cd = _giraffe_cube_get_wcs_transform(
self);
1357 crpix[GICUBE_X] = _giraffe_cube_get_wcs_origin(
self, GICUBE_X);
1358 crpix[GICUBE_Y] = _giraffe_cube_get_wcs_origin(
self, GICUBE_Y);
1359 crpix[GICUBE_Z] = _giraffe_cube_get_wcs_origin(
self, GICUBE_Z);
1361 crval[GICUBE_X] = _giraffe_cube_get_wcs_point(
self, GICUBE_X);
1362 crval[GICUBE_Y] = _giraffe_cube_get_wcs_point(
self, GICUBE_Y);
1363 crval[GICUBE_Z] = _giraffe_cube_get_wcs_point(
self, GICUBE_Z);
1365 ctype[GICUBE_X] = _giraffe_cube_get_wcs_axistype(
self, GICUBE_X);
1366 ctype[GICUBE_Y] = _giraffe_cube_get_wcs_axistype(
self, GICUBE_Y);
1367 ctype[GICUBE_Z] = _giraffe_cube_get_wcs_axistype(
self, GICUBE_Z);
1369 cunit[GICUBE_X] = _giraffe_cube_get_wcs_axisunit(
self, GICUBE_X);
1370 cunit[GICUBE_Y] = _giraffe_cube_get_wcs_axisunit(
self, GICUBE_Y);
1371 cunit[GICUBE_Z] = _giraffe_cube_get_wcs_axisunit(
self, GICUBE_Z);
1373 status = giraffe_propertylist_update_wcs(properties, GICUBE_AXES,
1374 crpix, crval, ctype, cunit,
1378 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1383 else if ((xaxis == TRUE) && (yaxis == TRUE) && (zaxis == TRUE)) {
1385 const cxchar* ctype[] = {
"PIXEL",
"PIXEL",
"AWAV"};
1386 const cxchar* cunit[] = {
"bin",
"bin",
"nm"};
1390 cxdouble crpix[] = {1., 1., 1.};
1391 cxdouble crval[] = {xstart, ystart, zstart};
1393 cpl_matrix* cd = cpl_matrix_new(3, 3);
1395 cpl_matrix_set(cd, 0, 0, xstep);
1396 cpl_matrix_set(cd, 1, 1, ystep);
1397 cpl_matrix_set(cd, 2, 2, zstep);
1399 status = giraffe_propertylist_update_wcs(properties, GICUBE_AXES,
1400 crpix, crval, ctype, cunit,
1404 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1408 cpl_matrix_delete(cd);
1414 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1424 giraffe_error_push();
1430 cpl_propertylist_update_string(properties, GIALIAS_BUNIT,
1433 cpl_propertylist_update_double(properties, GIALIAS_DATAMIN,
1434 cpl_array_get_min(pixels));
1435 cpl_propertylist_set_comment(properties, GIALIAS_DATAMIN,
1436 "Minimal pixel value");
1438 cpl_propertylist_update_double(properties, GIALIAS_DATAMAX,
1439 cpl_array_get_max(pixels));
1440 cpl_propertylist_set_comment(properties, GIALIAS_DATAMAX,
1441 "Maximum pixel value");
1443 cpl_propertylist_update_double(properties, GIALIAS_DATAMEAN,
1444 cpl_array_get_mean(pixels));
1445 cpl_propertylist_set_comment(properties, GIALIAS_DATAMEAN,
1446 "Mean of pixel values");
1448 cpl_propertylist_update_double(properties, GIALIAS_DATASIG,
1449 cpl_array_get_stdev(pixels));
1450 cpl_propertylist_set_comment(properties, GIALIAS_DATASIG,
1451 "Standard deviation of pixel values");
1453 cpl_propertylist_update_double(properties, GIALIAS_DATAMEDI,
1454 cpl_array_get_median(pixels));
1455 cpl_propertylist_set_comment(properties, GIALIAS_DATAMEDI,
1456 "Median of pixel values");
1458 cpl_array_unwrap((cpl_array*)pixels);
1461 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1465 giraffe_error_pop();
1472 giraffe_error_push();
1474 cpl_imagelist_save(self->planes, filename, CPL_BPP_IEEE_FLOAT,
1475 properties, iomode);
1477 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1481 giraffe_error_pop();