28 #include <cxmessages.h>
29 #include <cxstrutils.h>
31 #include <cpl_error.h>
32 #include <cpl_array.h>
33 #include <cpl_matrix.h>
34 #include <cpl_image.h>
35 #include <cpl_imagelist.h>
36 #include <cpl_propertylist.h>
59 typedef enum GiCubeAxes GiCubeAxes;
67 typedef struct GiCubeAxis GiCubeAxis;
71 cxdouble origin[GICUBE_AXES];
72 cxdouble point[GICUBE_AXES];
74 cxchar* axis_type[GICUBE_AXES];
75 cxchar* axis_unit[GICUBE_AXES];
77 cpl_matrix* transform;
80 typedef struct GiCubeWCS GiCubeWCS;
89 GiCubeAxis* axes[GICUBE_AXES];
95 cpl_imagelist* planes;
101 _giraffe_cube_clear_wcs(GiCube*
self)
104 register cxsize axis = 0;
106 for (axis = 0; axis < GICUBE_AXES; ++axis) {
108 if (self->wcs->axis_type[axis] != NULL) {
109 cx_free(self->wcs->axis_type[axis]);
110 self->wcs->axis_type[axis] = NULL;
113 if (self->wcs->axis_unit[axis] != NULL) {
114 cx_free(self->wcs->axis_unit[axis]);
115 self->wcs->axis_unit[axis] = NULL;
120 cpl_matrix_delete(self->wcs->transform);
121 self->wcs->transform = NULL;
132 _giraffe_cube_set_wcs(GiCube*
self,
const cpl_propertylist* axes,
133 const cpl_matrix* transform)
136 GiCubeWCS* wcs = NULL;
138 cx_assert(
self != NULL);
139 cx_assert(axes != NULL);
140 cx_assert(transform != NULL);
142 wcs = cx_malloc(
sizeof *self->wcs);
144 wcs->transform = cpl_matrix_duplicate(transform);
146 wcs->origin[GICUBE_X] = cpl_propertylist_get_double(axes,
"XORIGIN");
147 wcs->origin[GICUBE_Y] = cpl_propertylist_get_double(axes,
"YORIGIN");
148 wcs->origin[GICUBE_Z] = cpl_propertylist_get_double(axes,
"ZORIGIN");
150 wcs->point[GICUBE_X] = cpl_propertylist_get_double(axes,
"XPOINT");
151 wcs->point[GICUBE_Y] = cpl_propertylist_get_double(axes,
"YPOINT");
152 wcs->point[GICUBE_Z] = cpl_propertylist_get_double(axes,
"ZPOINT");
154 wcs->axis_type[GICUBE_X] =
155 cx_strdup(cpl_propertylist_get_string(axes,
"XTYPE"));
156 wcs->axis_type[GICUBE_Y] =
157 cx_strdup(cpl_propertylist_get_string(axes,
"YTYPE"));
158 wcs->axis_type[GICUBE_Z] =
159 cx_strdup(cpl_propertylist_get_string(axes,
"ZTYPE"));
161 wcs->axis_unit[GICUBE_X] =
162 cx_strdup(cpl_propertylist_get_string(axes,
"XUNIT"));
163 wcs->axis_unit[GICUBE_Y] =
164 cx_strdup(cpl_propertylist_get_string(axes,
"YUNIT"));
165 wcs->axis_unit[GICUBE_Z] =
166 cx_strdup(cpl_propertylist_get_string(axes,
"ZUNIT"));
169 if (self->wcs != NULL) {
170 _giraffe_cube_clear_wcs(
self);
180 inline static cxdouble
181 _giraffe_cube_get_wcs_origin(
const GiCube*
self, GiCubeAxes axis)
183 return self->wcs->origin[axis];
187 inline static cxdouble
188 _giraffe_cube_get_wcs_point(
const GiCube*
self, GiCubeAxes axis)
190 return self->wcs->point[axis];
194 inline static const cxchar*
195 _giraffe_cube_get_wcs_axistype(
const GiCube*
self, GiCubeAxes axis)
197 return self->wcs->axis_type[axis];
201 inline static const cxchar*
202 _giraffe_cube_get_wcs_axisunit(
const GiCube*
self, GiCubeAxes axis)
204 return self->wcs->axis_unit[axis];
208 inline static const cpl_matrix*
209 _giraffe_cube_get_wcs_transform(
const GiCube*
self)
211 return self->wcs->transform;
216 _giraffe_cube_set_size(GiCube*
self, cxsize width, cxsize height,
221 self->height = height;
224 self->size =
self->width *
self->height *
self->depth;
231 inline static GiCube*
232 _giraffe_cube_new(
void)
235 GiCube*
self = cx_malloc(
sizeof *
self);
239 _giraffe_cube_set_size(
self, 0, 0, 0);
241 self->axes[GICUBE_X] = NULL;
242 self->axes[GICUBE_Y] = NULL;
243 self->axes[GICUBE_Z] = NULL;
257 _giraffe_cube_init_planes(GiCube*
self)
260 register cxsize i = 0;
262 register cxdouble* base = NULL;
265 self->planes = cpl_imagelist_new();
266 cx_assert(self->planes != NULL);
271 for (i = 0; i <
self->depth; i++) {
273 cpl_image* plane = cpl_image_wrap_double(self->width, self->height,
276 cx_assert(plane != NULL);
277 cpl_imagelist_set(self->planes, plane, i);
279 base +=
self->width *
self->height;
289 _giraffe_cube_clear_planes(GiCube*
self)
292 register cxsize i = 0;
295 for (i = 0; i <
self->depth; i++) {
297 cpl_image* plane = cpl_imagelist_unset(self->planes, 0);
299 cpl_image_unwrap(plane);
303 cx_assert(cpl_imagelist_get_size(self->planes) == 0);
305 cpl_imagelist_delete(self->planes);
314 _giraffe_cube_delete(GiCube*
self)
317 register cxint i = 0;
319 for (i = 0; i < GICUBE_AXES; i++) {
320 if (self->axes[i] != NULL) {
321 cx_free(self->axes[i]);
322 self->axes[i] = NULL;
326 if (self->wcs != NULL) {
327 _giraffe_cube_clear_wcs(
self);
331 if (self->planes != NULL) {
332 _giraffe_cube_clear_planes(
self);
336 if (self->pixels != NULL) {
337 cx_free(self->pixels);
349 _giraffe_cube_has_axis(
const GiCube*
self, GiCubeAxes axis)
351 return (self->axes[axis] == NULL) ? FALSE : TRUE;
356 _giraffe_cube_get_axis(
const GiCube*
self, GiCubeAxes axis, cxdouble* start,
360 if (self->axes[axis] == NULL) {
366 *start =
self->axes[axis]->start;
370 *step =
self->axes[axis]->step;
381 _giraffe_cube_set_axis(GiCube*
self, GiCubeAxes axis, cxdouble start,
385 if (self->axes[axis] == NULL) {
386 self->axes[axis] = cx_calloc(1,
sizeof(GiCubeAxis));
389 cx_assert(self->axes[axis] != NULL);
391 self->axes[axis]->start = start;
392 self->axes[axis]->step = step;
415 return _giraffe_cube_new();
450 GiCube*
self = _giraffe_cube_new();
453 _giraffe_cube_set_size(
self, width, height, depth);
455 if (self->size == 0) {
456 _giraffe_cube_delete(
self);
464 self->pixels = cx_calloc(self->size,
sizeof(cxdouble));
467 cx_assert(self->pixels != NULL);
475 giraffe_error_push();
477 _giraffe_cube_init_planes(
self);
479 if (cpl_error_get_code() != CPL_ERROR_NONE) {
480 _giraffe_cube_delete(
self);
508 _giraffe_cube_delete(
self);
533 cx_assert(
self != NULL);
556 cx_assert(
self != NULL);
579 cx_assert(
self != NULL);
602 cx_assert(
self != NULL);
630 const cxchar*
const _id =
"giraffe_cube_set_size";
633 cx_assert(
self != NULL);
635 if ((width == 0) || (height == 0) || (depth == 0)) {
636 cpl_error_set(_id, CPL_ERROR_ILLEGAL_INPUT);
640 if ((self->width == width) && (self->height == height) &&
641 (self->depth == depth)) {
642 memset(self->pixels, 0, self->size *
sizeof(cxdouble));
650 if (self->planes != NULL) {
651 _giraffe_cube_clear_planes(
self);
654 if (self->pixels != NULL) {
655 cx_free(self->pixels);
663 _giraffe_cube_set_size(
self, width, height, depth);
671 self->pixels = cx_calloc(self->size,
sizeof(cxdouble));
672 cx_assert(self->pixels);
675 giraffe_error_push();
677 _giraffe_cube_init_planes(
self);
679 if (cpl_error_get_code() != CPL_ERROR_NONE) {
710 const cxchar*
const _id =
"giraffe_cube_get_data";
714 cpl_error_set(_id, CPL_ERROR_NULL_INPUT);
740 return _giraffe_cube_has_axis(
self, GICUBE_X);
761 return _giraffe_cube_has_axis(
self, GICUBE_Y);
782 return _giraffe_cube_has_axis(
self, GICUBE_Z);
803 return self->wcs != NULL;
831 cx_assert(
self != NULL);
833 return _giraffe_cube_get_axis(
self, GICUBE_X, start, step);
862 cx_assert(
self != NULL);
864 return _giraffe_cube_get_axis(
self, GICUBE_Y, start, step);
893 cx_assert(
self != NULL);
895 return _giraffe_cube_get_axis(
self, GICUBE_Z, start, step);
919 cx_assert(
self != NULL);
921 return _giraffe_cube_set_axis(
self, GICUBE_X, start, step);
945 cx_assert(
self != NULL);
947 return _giraffe_cube_set_axis(
self, GICUBE_Y, start, step);
971 cx_assert(
self != NULL);
973 return _giraffe_cube_set_axis(
self, GICUBE_Z, start, step);
996 if (self->wcs != NULL) {
997 _giraffe_cube_clear_wcs(
self);
1033 const cpl_matrix* transformation)
1036 cx_assert(
self != NULL);
1038 if ((axes == NULL) || (transformation == NULL)) {
1042 if ((cpl_matrix_get_nrow(transformation) != GICUBE_AXES) ||
1043 (cpl_matrix_get_ncol(transformation) != GICUBE_AXES)) {
1047 if ((cpl_propertylist_has(axes,
"XORIGIN") == FALSE) ||
1048 (cpl_propertylist_has(axes,
"YORIGIN") == FALSE) ||
1049 (cpl_propertylist_has(axes,
"ZORIGIN") == FALSE)) {
1053 if ((cpl_propertylist_has(axes,
"XPOINT") == FALSE) ||
1054 (cpl_propertylist_has(axes,
"YPOINT") == FALSE) ||
1055 (cpl_propertylist_has(axes,
"ZPOINT") == FALSE)) {
1059 if ((cpl_propertylist_has(axes,
"XTYPE") == FALSE) ||
1060 (cpl_propertylist_has(axes,
"YTYPE") == FALSE) ||
1061 (cpl_propertylist_has(axes,
"ZTYPE") == FALSE)) {
1065 if ((cpl_propertylist_has(axes,
"XUNIT") == FALSE) ||
1066 (cpl_propertylist_has(axes,
"YUNIT") == FALSE) ||
1067 (cpl_propertylist_has(axes,
"ZUNIT") == FALSE)) {
1071 _giraffe_cube_set_wcs(
self, axes, transformation);
1094 cpl_error_code status = CPL_ERROR_NONE;
1101 cx_assert(self->planes != NULL);
1103 status = cpl_imagelist_power(self->planes, 0.5);
1105 if (status != CPL_ERROR_NONE) {
1146 cxsize first = (cxsize)ceil(start);
1147 cxsize last = (cxsize)floor(end);
1149 cpl_image* image = NULL;
1158 if ((start >= end) || (start < 0.) || (end > depth)) {
1163 image = cpl_image_duplicate(cpl_imagelist_get(self->planes, first));
1165 if (image != NULL) {
1167 if (first == last) {
1168 cpl_image_multiply_scalar(image, (end - start));
1174 cxdouble fstart = first - start;
1175 cxdouble fend = end - last;
1178 for (i = first + 1; i < last; ++i) {
1179 cpl_image_add(image,
1180 cpl_imagelist_get_const(self->planes, i));
1189 if ((fstart > 0.) && (first > 0)) {
1190 cpl_image* tmp = cpl_imagelist_get(self->planes, first - 1);
1192 tmp = cpl_image_multiply_scalar_create(tmp, fstart);
1193 cpl_image_add(image, tmp);
1195 cpl_image_delete(tmp);
1199 if ((fend > 0.) && (last < depth)) {
1200 cpl_image* tmp = cpl_imagelist_get(self->planes, last);
1202 tmp = cpl_image_multiply_scalar_create(tmp, fend);
1203 cpl_image_add(image, tmp);
1205 cpl_image_delete(tmp);
1237 const cxchar* filename, cxcptr data)
1240 cxbool xaxis = FALSE;
1241 cxbool yaxis = FALSE;
1242 cxbool zaxis = FALSE;
1244 cxdouble xstart = 0.;
1245 cxdouble xstep = 0.;
1246 cxdouble ystart = 0.;
1247 cxdouble ystep = 0.;
1248 cxdouble zstart = 0.;
1249 cxdouble zstep = 0.;
1251 cxuint iomode = CPL_IO_CREATE;
1254 if (properties == NULL || filename == NULL) {
1264 iomode = *((cxuint*)data);
1277 if (iomode != CPL_IO_CREATE) {
1281 giraffe_error_push();
1283 cpl_propertylist_erase_regexp(properties,
"CRVAL[0-9]*", 0);
1284 cpl_propertylist_erase_regexp(properties,
"CRPIX[0-9]*", 0);
1285 cpl_propertylist_erase_regexp(properties,
"CDELT[0-9]*", 0);
1286 cpl_propertylist_erase_regexp(properties,
"CTYPE[0-9]*", 0);
1287 cpl_propertylist_erase_regexp(properties,
"CUNIT[0-9]*", 0);
1289 cpl_propertylist_erase(properties, GIALIAS_BUNIT);
1291 cpl_propertylist_erase(properties,
"DATAMIN");
1292 cpl_propertylist_erase(properties,
"DATAMAX");
1294 cpl_propertylist_erase(properties, GIALIAS_DATAMEAN);
1295 cpl_propertylist_erase(properties, GIALIAS_DATAMEDI);
1296 cpl_propertylist_erase(properties, GIALIAS_DATASIG);
1298 cpl_propertylist_save(properties, filename, iomode);
1300 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1304 giraffe_error_pop();
1311 const cpl_array* pixels = NULL;
1338 const cxchar* ctype[GICUBE_AXES];
1339 const cxchar* cunit[GICUBE_AXES];
1343 cxdouble crpix[GICUBE_AXES];
1344 cxdouble crval[GICUBE_AXES];
1346 const cpl_matrix* cd = _giraffe_cube_get_wcs_transform(
self);
1349 crpix[GICUBE_X] = _giraffe_cube_get_wcs_origin(
self, GICUBE_X);
1350 crpix[GICUBE_Y] = _giraffe_cube_get_wcs_origin(
self, GICUBE_Y);
1351 crpix[GICUBE_Z] = _giraffe_cube_get_wcs_origin(
self, GICUBE_Z);
1353 crval[GICUBE_X] = _giraffe_cube_get_wcs_point(
self, GICUBE_X);
1354 crval[GICUBE_Y] = _giraffe_cube_get_wcs_point(
self, GICUBE_Y);
1355 crval[GICUBE_Z] = _giraffe_cube_get_wcs_point(
self, GICUBE_Z);
1357 ctype[GICUBE_X] = _giraffe_cube_get_wcs_axistype(
self, GICUBE_X);
1358 ctype[GICUBE_Y] = _giraffe_cube_get_wcs_axistype(
self, GICUBE_Y);
1359 ctype[GICUBE_Z] = _giraffe_cube_get_wcs_axistype(
self, GICUBE_Z);
1361 cunit[GICUBE_X] = _giraffe_cube_get_wcs_axisunit(
self, GICUBE_X);
1362 cunit[GICUBE_Y] = _giraffe_cube_get_wcs_axisunit(
self, GICUBE_Y);
1363 cunit[GICUBE_Z] = _giraffe_cube_get_wcs_axisunit(
self, GICUBE_Z);
1365 status = giraffe_propertylist_update_wcs(properties, GICUBE_AXES,
1366 crpix, crval, ctype, cunit,
1370 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1375 else if ((xaxis == TRUE) && (yaxis == TRUE) && (zaxis == TRUE)) {
1377 const cxchar* ctype[] = {
"PIXEL",
"PIXEL",
"AWAV"};
1378 const cxchar* cunit[] = {
"bin",
"bin",
"nm"};
1382 cxdouble crpix[] = {1., 1., 1.};
1383 cxdouble crval[] = {xstart, ystart, zstart};
1385 cpl_matrix* cd = cpl_matrix_new(3, 3);
1387 cpl_matrix_set(cd, 0, 0, xstep);
1388 cpl_matrix_set(cd, 1, 1, ystep);
1389 cpl_matrix_set(cd, 2, 2, zstep);
1391 status = giraffe_propertylist_update_wcs(properties, GICUBE_AXES,
1392 crpix, crval, ctype, cunit,
1396 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1400 cpl_matrix_delete(cd);
1406 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1416 giraffe_error_push();
1422 cpl_propertylist_update_string(properties, GIALIAS_BUNIT,
1425 cpl_propertylist_update_double(properties, GIALIAS_DATAMIN,
1426 cpl_array_get_min(pixels));
1427 cpl_propertylist_set_comment(properties, GIALIAS_DATAMIN,
1428 "Minimal pixel value");
1430 cpl_propertylist_update_double(properties, GIALIAS_DATAMAX,
1431 cpl_array_get_max(pixels));
1432 cpl_propertylist_set_comment(properties, GIALIAS_DATAMAX,
1433 "Maximum pixel value");
1435 cpl_propertylist_update_double(properties, GIALIAS_DATAMEAN,
1436 cpl_array_get_mean(pixels));
1437 cpl_propertylist_set_comment(properties, GIALIAS_DATAMEAN,
1438 "Mean of pixel values");
1440 cpl_propertylist_update_double(properties, GIALIAS_DATASIG,
1441 cpl_array_get_stdev(pixels));
1442 cpl_propertylist_set_comment(properties, GIALIAS_DATASIG,
1443 "Standard deviation of pixel values");
1445 cpl_propertylist_update_double(properties, GIALIAS_DATAMEDI,
1446 cpl_array_get_median(pixels));
1447 cpl_propertylist_set_comment(properties, GIALIAS_DATAMEDI,
1448 "Median of pixel values");
1450 cpl_array_unwrap((cpl_array*)pixels);
1453 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1457 giraffe_error_pop();
1464 giraffe_error_push();
1466 cpl_imagelist_save(self->planes, filename, CPL_BPP_IEEE_FLOAT,
1467 properties, iomode);
1469 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1473 giraffe_error_pop();
cxint giraffe_cube_get_xaxis(const GiCube *self, cxdouble *start, cxdouble *step)
Get the data cube's x-axis start value and step size.
cxbool giraffe_cube_has_yaxis(const GiCube *self)
Check whether a y-axis is defined for the given cube.
cxsize giraffe_cube_get_width(const GiCube *self)
Get the width of the given data cube.
cxint giraffe_cube_get_yaxis(const GiCube *self, cxdouble *start, cxdouble *step)
Get the data cube's y-axis start value and step size.
cxint giraffe_cube_set_size(GiCube *self, cxsize width, cxsize height, cxsize depth)
Set the size of a data cube.
cxsize giraffe_cube_get_depth(const GiCube *self)
Get the depth of the given data cube.
cxbool giraffe_cube_has_zaxis(const GiCube *self)
Check whether a z-axis is defined for the given cube.
cxint giraffe_cube_set_yaxis(GiCube *self, cxdouble start, cxdouble step)
Set the data cube's y-axis start value and step size.
cxint giraffe_cube_get_zaxis(const GiCube *self, cxdouble *start, cxdouble *step)
Get the data cube's z-axis start value and step size.
cxint giraffe_cube_set_wcs(GiCube *self, const cpl_propertylist *axes, const cpl_matrix *transformation)
Set the data cube's world coordinate system.
void giraffe_cube_clear_wcs(GiCube *self)
Remove the world coordinate system from the cube.
cxint giraffe_cube_set_zaxis(GiCube *self, cxdouble start, cxdouble step)
Set the data cube's z-axis start value and step size.
cxint giraffe_cube_set_xaxis(GiCube *self, cxdouble start, cxdouble step)
Set the data cube's x-axis start value and step size.
void giraffe_cube_delete(GiCube *self)
Destroys a cube object.
GiCube * giraffe_cube_new(void)
Create an empty data cube.
cxint giraffe_cube_save(const GiCube *self, cpl_propertylist *properties, const cxchar *filename, cxcptr data)
Save the given data cube to disk.
GiCube * giraffe_cube_create(cxsize width, cxsize height, cxsize depth, cxdouble *data)
Create a data cube with the given width, height and depth.
cxsize giraffe_cube_get_height(const GiCube *self)
Get the height of the given data cube.
cpl_image * giraffe_cube_integrate(const GiCube *self, cxdouble start, cxdouble end)
Integrate a cube along the z-axis.
cxint giraffe_cube_sqrt(GiCube *self)
Compute the square root of the elements of a cube.
cxbool giraffe_cube_has_wcs(const GiCube *self)
Check whether a world coordinate system is defined for the given cube.
cxsize giraffe_cube_get_size(const GiCube *self)
Get the size of the given data cube.
cxbool giraffe_cube_has_xaxis(const GiCube *self)
Check whether an x-axis is defined for the given cube.
cxdouble * giraffe_cube_get_data(const GiCube *self)
Get a reference to the data cube's pixel buffer.