00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 # include <config.h>
00030 #endif
00031
00032 #include <string.h>
00033 #include <math.h>
00034
00035 #include <cxmemory.h>
00036 #include <cxmessages.h>
00037
00038 #include <cpl_error.h>
00039 #include <cpl_array.h>
00040 #include <cpl_image.h>
00041 #include <cpl_imagelist.h>
00042 #include <cpl_propertylist.h>
00043
00044 #include "gialias.h"
00045 #include "gierror.h"
00046 #include "gicube.h"
00047 #include "giutils.h"
00048
00049
00058 enum GiCubeAxes {
00059 GICUBE_X = 0,
00060 GICUBE_Y = 1,
00061 GICUBE_Z = 2,
00062 GICUBE_AXES
00063 };
00064
00065 typedef enum GiCubeAxes GiCubeAxes;
00066
00067
00068 struct GiCubeAxis {
00069 cxdouble start;
00070 cxdouble step;
00071 };
00072
00073 typedef struct GiCubeAxis GiCubeAxis;
00074
00075
00076 struct GiCube {
00077 cxsize width;
00078 cxsize height;
00079 cxsize depth;
00080 cxsize size;
00081
00082 GiCubeAxis* axes[GICUBE_AXES];
00083
00084 cxdouble* pixels;
00085
00086 cpl_imagelist* planes;
00087 };
00088
00089
00090 inline static void
00091 _giraffe_cube_set_size(GiCube* self, cxsize width, cxsize height,
00092 cxsize depth)
00093 {
00094
00095 self->width = width;
00096 self->height = height;
00097 self->depth = depth;
00098
00099 self->size = self->width * self->height * self->depth;
00100
00101 return;
00102
00103 }
00104
00105
00106 inline static GiCube*
00107 _giraffe_cube_new(void)
00108 {
00109
00110 GiCube* self = cx_malloc(sizeof *self);
00111
00112
00113 if (self != NULL) {
00114 _giraffe_cube_set_size(self, 0, 0, 0);
00115
00116 self->axes[GICUBE_X] = NULL;
00117 self->axes[GICUBE_Y] = NULL;
00118 self->axes[GICUBE_Z] = NULL;
00119
00120 self->pixels = NULL;
00121 self->planes = NULL;
00122 }
00123
00124 return self;
00125
00126 }
00127
00128
00129 inline static cxint
00130 _giraffe_cube_init_planes(GiCube* self)
00131 {
00132
00133 register cxsize i = 0;
00134
00135 register cxdouble* base = NULL;
00136
00137
00138 self->planes = cpl_imagelist_new();
00139 cx_assert(self->planes != NULL);
00140
00141
00142 base = self->pixels;
00143
00144 for (i = 0; i < self->depth; i++) {
00145
00146 cpl_image* plane = cpl_image_wrap_double(self->width, self->height,
00147 base);
00148
00149 cx_assert(plane != NULL);
00150 cpl_imagelist_set(self->planes, plane, i);
00151
00152 base += self->width * self->height;
00153
00154 }
00155
00156 return 0;
00157
00158 }
00159
00160
00161 inline static void
00162 _giraffe_cube_clear_planes(GiCube* self)
00163 {
00164
00165 register cxsize i = 0;
00166
00167
00168 for (i = 0; i < self->depth; i++) {
00169
00170 cpl_image* plane = cpl_imagelist_unset(self->planes, 0);
00171
00172 cpl_image_unwrap(plane);
00173
00174 }
00175
00176 cx_assert(cpl_imagelist_get_size(self->planes) == 0);
00177
00178 cpl_imagelist_delete(self->planes);
00179 self->planes =NULL;
00180
00181 return;
00182
00183 }
00184
00185
00186 inline static void
00187 _giraffe_cube_delete(GiCube* self)
00188 {
00189
00190 register cxint i = 0;
00191
00192 for (i = 0; i < GICUBE_AXES; i++) {
00193 if (self->axes[i] != NULL) {
00194 cx_free(self->axes[i]);
00195 self->axes[i] = NULL;
00196 }
00197 }
00198
00199 if (self->planes != NULL) {
00200 _giraffe_cube_clear_planes(self);
00201 self->planes = NULL;
00202 }
00203
00204 if (self->pixels != NULL) {
00205 cx_free(self->pixels);
00206 self->pixels = NULL;
00207 }
00208
00209 cx_free(self);
00210
00211 return;
00212
00213 }
00214
00215
00216 inline static cxbool
00217 _giraffe_cube_has_axis(const GiCube* self, GiCubeAxes axis)
00218 {
00219 return (self->axes[axis] == NULL) ? FALSE : TRUE;
00220 }
00221
00222
00223 inline static cxint
00224 _giraffe_cube_get_axis(const GiCube* self, GiCubeAxes axis, cxdouble* start,
00225 cxdouble* step)
00226 {
00227
00228 if (self->axes[axis] == NULL) {
00229 return 1;
00230 }
00231 else {
00232
00233 if (start != NULL) {
00234 *start = self->axes[axis]->start;
00235 }
00236
00237 if (step != NULL) {
00238 *step = self->axes[axis]->step;
00239 }
00240
00241 }
00242
00243 return 0;
00244
00245 }
00246
00247
00248 inline static cxint
00249 _giraffe_cube_set_axis(GiCube* self, GiCubeAxes axis, cxdouble start,
00250 cxdouble step)
00251 {
00252
00253 if (self->axes[axis] == NULL) {
00254 self->axes[axis] = cx_calloc(1, sizeof(GiCubeAxis));
00255 }
00256
00257 cx_assert(self->axes[axis] != NULL);
00258
00259 self->axes[axis]->start = start;
00260 self->axes[axis]->step = step;
00261
00262 return 0;
00263
00264 }
00265
00266
00279 GiCube*
00280 giraffe_cube_new(void)
00281 {
00282
00283 return _giraffe_cube_new();
00284
00285 }
00286
00287
00314 GiCube*
00315 giraffe_cube_create(cxsize width, cxsize height, cxsize depth, cxdouble* data)
00316 {
00317
00318 GiCube* self = _giraffe_cube_new();
00319
00320
00321 _giraffe_cube_set_size(self, width, height, depth);
00322
00323 if (self->size == 0) {
00324 _giraffe_cube_delete(self);
00325 return NULL;
00326 }
00327
00328 if (data != NULL) {
00329 self->pixels = data;
00330 }
00331 else {
00332 self->pixels = cx_calloc(self->size, sizeof(cxdouble));
00333 }
00334
00335 cx_assert(self->pixels != NULL);
00336
00337
00338
00339
00340
00341
00342
00343 giraffe_error_push();
00344
00345 _giraffe_cube_init_planes(self);
00346
00347 if (cpl_error_get_code() != CPL_ERROR_NONE) {
00348 _giraffe_cube_delete(self);
00349 return NULL;
00350 }
00351
00352 giraffe_error_pop();
00353
00354 return self;
00355
00356 }
00357
00358
00371 void
00372 giraffe_cube_delete(GiCube* self)
00373 {
00374
00375 if (self != NULL) {
00376 _giraffe_cube_delete(self);
00377 }
00378
00379 return;
00380
00381 }
00382
00383
00397 cxsize
00398 giraffe_cube_get_width(const GiCube* self)
00399 {
00400
00401 cx_assert(self != NULL);
00402 return self->width;
00403
00404 }
00405
00406
00420 cxsize
00421 giraffe_cube_get_height(const GiCube* self)
00422 {
00423
00424 cx_assert(self != NULL);
00425 return self->height;
00426
00427 }
00428
00429
00443 cxsize
00444 giraffe_cube_get_depth(const GiCube* self)
00445 {
00446
00447 cx_assert(self != NULL);
00448 return self->depth;
00449
00450 }
00451
00452
00466 cxsize
00467 giraffe_cube_get_size(const GiCube* self)
00468 {
00469
00470 cx_assert(self != NULL);
00471 return self->size;
00472
00473 }
00474
00475
00494 cxint
00495 giraffe_cube_set_size(GiCube* self, cxsize width, cxsize height, cxsize depth)
00496 {
00497
00498 const cxchar* const _id = "giraffe_cube_set_size";
00499
00500
00501 cx_assert(self != NULL);
00502
00503 if ((width == 0) || (height == 0) || (depth == 0)) {
00504 cpl_error_set(_id, CPL_ERROR_ILLEGAL_INPUT);
00505 return 1;
00506 }
00507
00508 if ((self->width == width) && (self->height == height) &&
00509 (self->depth == depth)) {
00510 memset(self->pixels, 0, self->size * sizeof(cxdouble));
00511 }
00512 else {
00513
00514
00515
00516
00517
00518 if (self->planes != NULL) {
00519 _giraffe_cube_clear_planes(self);
00520 }
00521
00522 if (self->pixels != NULL) {
00523 cx_free(self->pixels);
00524 }
00525
00526
00527
00528
00529
00530
00531 _giraffe_cube_set_size(self, width, height, depth);
00532
00533
00534
00535
00536
00537
00538
00539 self->pixels = cx_calloc(self->size, sizeof(cxdouble));
00540 cx_assert(self->pixels);
00541
00542
00543 giraffe_error_push();
00544
00545 _giraffe_cube_init_planes(self);
00546
00547 if (cpl_error_get_code() != CPL_ERROR_NONE) {
00548 return 1;
00549 }
00550
00551 giraffe_error_pop();
00552
00553 }
00554
00555 return 0;
00556
00557 }
00558
00559
00574 cxdouble*
00575 giraffe_cube_get_data(const GiCube* self)
00576 {
00577
00578 const cxchar* const _id = "giraffe_cube_get_data";
00579
00580
00581 if (self == NULL) {
00582 cpl_error_set(_id, CPL_ERROR_NULL_INPUT);
00583 return 0;
00584 }
00585
00586 return self->pixels;
00587
00588 }
00589
00590
00605 cxbool
00606 giraffe_cube_has_xaxis(const GiCube* self)
00607 {
00608 return _giraffe_cube_has_axis(self, GICUBE_X);
00609 }
00610
00611
00626 cxbool
00627 giraffe_cube_has_yaxis(const GiCube* self)
00628 {
00629 return _giraffe_cube_has_axis(self, GICUBE_Y);
00630 }
00631
00632
00647 cxbool
00648 giraffe_cube_has_zaxis(const GiCube* self)
00649 {
00650 return _giraffe_cube_has_axis(self, GICUBE_Z);
00651 }
00652
00653
00674 cxint
00675 giraffe_cube_get_xaxis(const GiCube* self, cxdouble* start, cxdouble* step)
00676 {
00677
00678 cx_assert(self != NULL);
00679
00680 return _giraffe_cube_get_axis(self, GICUBE_X, start, step);
00681
00682 }
00683
00684
00705 cxint
00706 giraffe_cube_get_yaxis(const GiCube* self, cxdouble* start, cxdouble* step)
00707 {
00708
00709 cx_assert(self != NULL);
00710
00711 return _giraffe_cube_get_axis(self, GICUBE_Y, start, step);
00712
00713 }
00714
00715
00736 cxint
00737 giraffe_cube_get_zaxis(const GiCube* self, cxdouble* start, cxdouble* step)
00738 {
00739
00740 cx_assert(self != NULL);
00741
00742 return _giraffe_cube_get_axis(self, GICUBE_Z, start, step);
00743
00744 }
00745
00746
00762 cxint
00763 giraffe_cube_set_xaxis(GiCube* self, cxdouble start, cxdouble step)
00764 {
00765
00766 cx_assert(self != NULL);
00767
00768 return _giraffe_cube_set_axis(self, GICUBE_X, start, step);
00769
00770 }
00771
00772
00788 cxint
00789 giraffe_cube_set_yaxis(GiCube* self, cxdouble start, cxdouble step)
00790 {
00791
00792 cx_assert(self != NULL);
00793
00794 return _giraffe_cube_set_axis(self, GICUBE_Y, start, step);
00795
00796 }
00797
00798
00814 cxint
00815 giraffe_cube_set_zaxis(GiCube* self, cxdouble start, cxdouble step)
00816 {
00817
00818 cx_assert(self != NULL);
00819
00820 return _giraffe_cube_set_axis(self, GICUBE_Z, start, step);
00821
00822 }
00823
00824
00838 cxint
00839 giraffe_cube_sqrt(GiCube* self)
00840 {
00841
00842 cpl_error_code status = CPL_ERROR_NONE;
00843
00844
00845 if (self == NULL) {
00846 return -1;
00847 }
00848
00849 cx_assert(self->planes != NULL);
00850
00851 status = cpl_imagelist_power(self->planes, 0.5);
00852
00853 if (status != CPL_ERROR_NONE) {
00854 return 1;
00855 }
00856
00857 return 0;
00858
00859 }
00860
00861
00889 cpl_image*
00890 giraffe_cube_integrate(const GiCube* self, cxdouble start, cxdouble end)
00891 {
00892
00893 cxsize depth = 0;
00894 cxsize first = (cxsize)ceil(start);
00895 cxsize last = (cxsize)floor(end);
00896
00897 cpl_image* image = NULL;
00898
00899
00900 if (self == NULL) {
00901 return NULL;
00902 }
00903
00904 depth = giraffe_cube_get_depth(self);
00905
00906 if ((start >= end) || (start < 0.) || (end > depth)) {
00907 return NULL;
00908 }
00909
00910
00911 image = cpl_image_duplicate(cpl_imagelist_get(self->planes, first));
00912
00913 if (image != NULL) {
00914
00915 if (first == last) {
00916 cpl_image_multiply_scalar(image, (end - start));
00917 }
00918 else {
00919
00920 cxsize i = 0;
00921
00922 cxdouble fstart = first - start;
00923 cxdouble fend = end - last;
00924
00925
00926 for (i = first + 1; i < last; ++i) {
00927 cpl_image_add(image,
00928 cpl_imagelist_get_const(self->planes, i));
00929 }
00930
00931
00932
00933
00934
00935
00936
00937 if ((fstart > 0.) && (first > 0)) {
00938 cpl_image* tmp = cpl_imagelist_get(self->planes, first - 1);
00939
00940 tmp = cpl_image_multiply_scalar_create(tmp, fstart);
00941 cpl_image_add(image, tmp);
00942
00943 cpl_image_delete(tmp);
00944 tmp = NULL;
00945 }
00946
00947 if ((fend > 0.) && (last < depth)) {
00948 cpl_image* tmp = cpl_imagelist_get(self->planes, last);
00949
00950 tmp = cpl_image_multiply_scalar_create(tmp, fend);
00951 cpl_image_add(image, tmp);
00952
00953 cpl_image_delete(tmp);
00954 tmp = NULL;
00955 }
00956
00957 }
00958
00959 }
00960
00961 return image;
00962
00963 }
00964
00965
00983 cxint
00984 giraffe_cube_save(const GiCube* self, cpl_propertylist* properties,
00985 const cxchar* filename, cxcptr data)
00986 {
00987
00988 cxbool xaxis = FALSE;
00989 cxbool yaxis = FALSE;
00990 cxbool zaxis = FALSE;
00991
00992 cxdouble xstart = 0.;
00993 cxdouble xstep = 0.;
00994 cxdouble ystart = 0.;
00995 cxdouble ystep = 0.;
00996 cxdouble zstart = 0.;
00997 cxdouble zstep = 0.;
00998
00999 cxuint iomode = CPL_IO_CREATE;
01000
01001
01002 if (properties == NULL || filename == NULL) {
01003 return -1;
01004 }
01005
01006
01007
01008
01009
01010
01011 if (data != NULL) {
01012 iomode = *((cxuint*)data);
01013 }
01014
01015
01016 if (self == NULL) {
01017
01018
01019
01020
01021
01022
01023
01024
01025 if (iomode != CPL_IO_CREATE) {
01026 return -2;
01027 }
01028
01029 giraffe_error_push();
01030
01031 cpl_propertylist_erase_regexp(properties, "CRVAL[0-9]*", 0);
01032 cpl_propertylist_erase_regexp(properties, "CRPIX[0-9]*", 0);
01033 cpl_propertylist_erase_regexp(properties, "CDELT[0-9]*", 0);
01034 cpl_propertylist_erase_regexp(properties, "CTYPE[0-9]*", 0);
01035
01036 cpl_propertylist_erase(properties, "DATAMIN");
01037 cpl_propertylist_erase(properties, "DATAMAX");
01038
01039 cpl_propertylist_erase(properties, GIALIAS_DATAMEAN);
01040 cpl_propertylist_erase(properties, GIALIAS_DATAMEDI);
01041 cpl_propertylist_erase(properties, GIALIAS_DATASIG);
01042
01043 cpl_propertylist_save(properties, filename, iomode);
01044
01045 if (cpl_error_get_code() != CPL_ERROR_NONE) {
01046 return 1;
01047 }
01048
01049 giraffe_error_pop();
01050
01051 }
01052 else {
01053
01054 cxsize size = 0;
01055
01056 const cpl_array* pixels = NULL;
01057
01058
01059
01060
01061
01062
01063
01064 if (giraffe_cube_get_xaxis(self, &xstart, &xstep) == 0) {
01065 xaxis = TRUE;
01066 }
01067
01068 if (giraffe_cube_get_yaxis(self, &ystart, &ystep) == 0) {
01069 yaxis = TRUE;
01070 }
01071
01072 if (giraffe_cube_get_zaxis(self, &zstart, &zstep) == 0) {
01073 zaxis = TRUE;
01074 }
01075
01076
01077 if ((xaxis == TRUE) && (yaxis == TRUE) && (zaxis == TRUE)) {
01078
01079 const cxchar* ctype[] = {"PIXEL", "PIXEL", "WAVE"};
01080 const cxchar* cunit[] = {"pixel", "pixel", "nm"};
01081
01082 cxint status = 0;
01083
01084 cxdouble crpix[] = {1., 1., 1.};
01085 cxdouble crval[] = {xstart, ystart, zstart};
01086
01087 cpl_matrix* cd = cpl_matrix_new(3, 3);
01088
01089 cpl_matrix_set(cd, 0, 0, xstep);
01090 cpl_matrix_set(cd, 1, 1, ystep);
01091 cpl_matrix_set(cd, 2, 2, zstep);
01092
01093 status = giraffe_propertylist_update_wcs(properties, 3, crpix, crval,
01094 ctype, cunit, cd);
01095
01096 if (status != 0) {
01097 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
01098 NULL, NULL);
01099 }
01100
01101 cpl_matrix_delete(cd);
01102 cd = NULL;
01103
01104 }
01105 else {
01106
01107 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
01108 NULL, NULL);
01109
01110 }
01111
01112
01113
01114
01115
01116
01117 giraffe_error_push();
01118
01119 size = giraffe_cube_get_size(self);
01120 pixels = cpl_array_wrap_double(giraffe_cube_get_data(self), size);
01121
01122
01123 cpl_propertylist_update_double(properties, GIALIAS_DATAMIN,
01124 cpl_array_get_min(pixels));
01125 cpl_propertylist_set_comment(properties, GIALIAS_DATAMIN,
01126 "Minimal pixel value");
01127
01128 cpl_propertylist_update_double(properties, GIALIAS_DATAMAX,
01129 cpl_array_get_max(pixels));
01130 cpl_propertylist_set_comment(properties, GIALIAS_DATAMAX,
01131 "Maximum pixel value");
01132
01133 cpl_propertylist_update_double(properties, GIALIAS_DATAMEAN,
01134 cpl_array_get_mean(pixels));
01135 cpl_propertylist_set_comment(properties, GIALIAS_DATAMEAN,
01136 "Mean of pixel values");
01137
01138 cpl_propertylist_update_double(properties, GIALIAS_DATASIG,
01139 cpl_array_get_stdev(pixels));
01140 cpl_propertylist_set_comment(properties, GIALIAS_DATASIG,
01141 "Standard deviation of pixel values");
01142
01143 cpl_propertylist_update_double(properties, GIALIAS_DATAMEDI,
01144 cpl_array_get_median(pixels));
01145 cpl_propertylist_set_comment(properties, GIALIAS_DATAMEDI,
01146 "Median of pixel values");
01147
01148 cpl_array_unwrap((cpl_array*)pixels);
01149 pixels = NULL;
01150
01151 if (cpl_error_get_code() != CPL_ERROR_NONE) {
01152 return 1;
01153 }
01154
01155 giraffe_error_pop();
01156
01157
01158
01159
01160
01161
01162 giraffe_error_push();
01163
01164 cpl_imagelist_save(self->planes, filename, CPL_BPP_IEEE_FLOAT,
01165 properties, iomode);
01166
01167 if (cpl_error_get_code() != CPL_ERROR_NONE) {
01168 return 1;
01169 }
01170
01171 giraffe_error_pop();
01172
01173 }
01174
01175 return 0;
01176
01177 }