1 /*
2  # This file is part of the Astrometry.net suite.
3  # Licensed under a 3-clause BSD style license - see LICENSE
4  */
5 %module(package="astrometry.plot") plotstuff_c
6 
7 %include <typemaps.i>
8 
9 %import "util.i"
10 
11 #undef ATTRIB_FORMAT
12 #define ATTRIB_FORMAT(x,y,z)
13 #undef WarnUnusedResult
14 #define WarnUnusedResult
15 %{
16 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
17 #include <numpy/arrayobject.h>
18 #include <stdlib.h>
19 #include <math.h>
20 
21 #include "os-features.h"
22 #include "plotstuff.h"
23 #include "plotimage.h"
24 #include "plotoutline.h"
25 #include "plotgrid.h"
26 #include "plotindex.h"
27 #include "plotxy.h"
28 #include "plotradec.h"
29 #include "plotmatch.h"
30 #include "plotannotations.h"
31 #include "plothealpix.h"
32 #include "sip.h"
33 #include "sip-utils.h"
34 #include "sip_qfits.h"
35 #include "log.h"
36 #include "fitsioutils.h"
37 #include "anwcs.h"
38 #include "coadd.h"
39 #include "anqfits.h"
40 #include "mathutil.h"
41 #include "convolve-image.h"
42 #include "resample.h"
43 #include "cairoutils.h"
44 #include "an-bool.h"
45 
46 
47 #define true 1
48 #define false 0
49     %}
50 
51 %apply double *OUTPUT { double *pramin, double *pramax, double *pdecmin, double *pdecmax };
52 %apply double *OUTPUT { double *pra, double *pdec };
53 %apply double *OUTPUT { double *pradius };
54 %apply double *OUTPUT { double *pra, double *pdec, double *pradius };
55 %apply double *OUTPUT { double *p_x, double *p_y };
56 %apply int *OUTPUT { int* p_r, int* p_g, int* p_b, int* p_a };
57 
58 %include "plotstuff.h"
59 %include "coadd.h"
60 %include "qfits_image.h"
61 %include "fitsioutils.h"
62 %include "convolve-image.h"
63 
64  /*
65   number* coadd_create_weight_image_from_range(const number* img, int W, int H,
66   number lowval, number highval);
67   */
68 
69 %inline %{
c_image_numpy_view(float * data,int nx,int ny)70     PyObject* c_image_numpy_view(float* data, int nx, int ny) {
71         npy_intp dims[2];
72         dims[0] = ny;
73         dims[1] = nx;
74         return PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, data);
75     }
76 %}
77 
78 %pythoncode %{
79     def qfits_load_image(fn, ext=1, plane=0, map=1, ptype=PTYPE_FLOAT):
80         ld = qfitsloader()
81         ld.filename = fn
82         ld.xtnum = ext
83         ld.pnum = plane
84         ld.map = map
85         ld.ptype = ptype
86         if qfitsloader_init(ld):
87             raise RuntimeError('qfitsloader_init(file "%s", ext %i) failed' % (fn, ext))
88         if qfits_loadpix(ld):
89             raise RuntimeError('qfits_loadpix(file "%s", ext %i) failed' % (fn, ext))
90 
91         class qfits_image(object):
92             def __init__(self, pix, nx, ny, ld):
93                 self.pix = pix
94                 self.nx = nx
95                 self.ny = ny
96                 self.ld = ld
97             def __del__(self):
98                 qfitsloader_free_buffer(self.ld)
99 
100         return qfits_image(ld.fbuf, ld.lx, ld.ly, ld)
101 %}
102 
103 void free(void* ptr);
104 
105 %apply int* OUTPUT { int* newW, int* newH };
106 #define Const
107 #define InlineDeclare
108 %include "mathutil.h"
109 #undef Const
110 #undef InlineDeclare
111 
112  /* Set the input argument to point to a temporary variable */
113 %typemap(in, numinputs=0) unsigned char* rgbout (unsigned char temp[3]) {
114     $1 = temp;
115 }
116 
117 %typemap(argout) unsigned char* rgbout {
118     // Append output value $1 to $result
119     if (result) {
120         Py_DECREF($result);
121         $result = Py_None;
122     } else {
123         int i;
124         Py_DECREF($result);
125         $result = PyList_New(3);
126         for (i=0; i<3; i++) {
127             PyObject *o = PyInt_FromLong((long)$1[i]);
128             PyList_SetItem($result,i,o);
129         }
130     }
131 }
132 
133 %typemap(in) int rgb[3] (int temp[3]) {
134     int i;
135     // Convert sequence of ints to int[3]
136     if (!PySequence_Check($input) ||
137         (PySequence_Length($input) != 3)) {
138         PyErr_SetString(PyExc_ValueError,"Expected a sequence of length 3");
139         return NULL;
140     }
141     for (i=0; i<3; i++) {
142         PyObject *o = PySequence_GetItem($input, i);
143         if (PyNumber_Check(o)) {
144             temp[i] = (int)PyInt_AsLong(o);
145         } else {
146             PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");
147             return NULL;
148         }
149     }
150     $1 = temp;
151 }
152 
153 %include "plotimage.h"
154 %include "plotoutline.h"
155 %include "plotgrid.h"
156 %include "plotindex.h"
157 %include "plotxy.h"
158 %include "plotradec.h"
159 %include "plotmatch.h"
160 %include "plotannotations.h"
161 %include "plothealpix.h"
162 %include "sip.h"
163 %include "sip_qfits.h"
164 %include "sip-utils.h"
165 %include "anwcs.h"
166 
167 %init %{
168     import_array();
169 %}
170 
171 // HACK!
172 enum cairo_op {
173     CAIRO_OPERATOR_CLEAR,
174     CAIRO_OPERATOR_SOURCE,
175     CAIRO_OPERATOR_OVER,
176     CAIRO_OPERATOR_IN,
177     CAIRO_OPERATOR_OUT,
178     CAIRO_OPERATOR_ATOP,
179     CAIRO_OPERATOR_DEST,
180     CAIRO_OPERATOR_DEST_OVER,
181     CAIRO_OPERATOR_DEST_IN,
182     CAIRO_OPERATOR_DEST_OUT,
183     CAIRO_OPERATOR_DEST_ATOP,
184     CAIRO_OPERATOR_XOR,
185     CAIRO_OPERATOR_ADD,
186     CAIRO_OPERATOR_SATURATE,
187     // Since cairo 1.10
188     CAIRO_OPERATOR_MULTIPLY,
189     CAIRO_OPERATOR_SCREEN,
190     CAIRO_OPERATOR_OVERLAY,
191     CAIRO_OPERATOR_DARKEN,
192     CAIRO_OPERATOR_LIGHTEN,
193     CAIRO_OPERATOR_COLOR_DODGE,
194     CAIRO_OPERATOR_COLOR_BURN,
195     CAIRO_OPERATOR_HARD_LIGHT,
196     CAIRO_OPERATOR_SOFT_LIGHT,
197     CAIRO_OPERATOR_DIFFERENCE,
198     CAIRO_OPERATOR_EXCLUSION,
199     CAIRO_OPERATOR_HSL_HUE,
200     CAIRO_OPERATOR_HSL_SATURATION,
201     CAIRO_OPERATOR_HSL_COLOR,
202     CAIRO_OPERATOR_HSL_LUMINOSITY
203 };
204 typedef enum cairo_op cairo_operator_t;
205 
206 %{
207     sip_t* new_sip_t(double crpix1, double crpix2, double crval1, double crval2,
208                      double cd11, double cd12, double cd21, double cd22) {
209         sip_t* sip = sip_create();
210         tan_t* tan = &(sip->wcstan);
211         tan->crpix[0] = crpix1;
212         tan->crpix[1] = crpix2;
213         tan->crval[0] = crval1;
214         tan->crval[1] = crval2;
215         tan->cd[0][0] = cd11;
216         tan->cd[0][1] = cd12;
217         tan->cd[1][0] = cd21;
218         tan->cd[1][1] = cd22;
219         return sip;
220     }
221 %}
222 
223 %extend sip_t {
224     sip_t(double, double, double, double, double, double, double, double);
225 
226     double crval1() {
227         return self->wcstan.crval[0];
228     }
229     double crval2() {
230         return self->wcstan.crval[1];
231     }
232     double crpix1() {
233         return self->wcstan.crpix[0];
234     }
235     double crpix2() {
236         return self->wcstan.crpix[1];
237     }
238     double cd11() {
239         return self->wcstan.cd[0][0];
240     }
241     double cd12() {
242         return self->wcstan.cd[0][1];
243     }
244     double cd21() {
245         return self->wcstan.cd[1][0];
246     }
247     double cd22() {
248         return self->wcstan.cd[1][1];
249     }
250 }
251 
252 %inline %{
253     void image_debug(float* img, int W, int H) {
254         int i;
255         double mn,mx;
256         mn = 1e300;
257         mx = -1e300;
258         for (i=0; i<(W*H); i++) {
259             mn = MIN(mn, img[i]);
260             mx = MAX(mx, img[i]);
261         }
262         logmsg("Image min,max %g,%g\n", mn,mx);
263     }
264 
265     void image_add(float* img, int W, int H, float val) {
266         int i;
267         for (i=0; i<(W*H); i++)
268             img[i] += val;
269     }
270 
271     void image_weighted_smooth(float* img, int W, int H, const float* weight,
272                                float sigma) {
273         int K0, NK;
274         float* kernel = convolve_get_gaussian_kernel_f(sigma, 5., &K0, &NK);
275         convolve_separable_weighted_f(img, W, H, weight, kernel, K0, NK, img, NULL);
276         free(kernel);
277     }
278 %}
279 
280 %extend plot_args {
281     PyObject* view_image_as_numpy() {
282         npy_intp dim[3];
283         unsigned char* img;
284         PyObject* npimg;
285         dim[0] = self->H;
286         dim[1] = self->W;
287         dim[2] = 4;
288         img = cairo_image_surface_get_data(self->target);
289         npimg = PyArray_SimpleNewFromData(3, dim, NPY_UBYTE, img);
290         return npimg;
291     }
292 
293     PyObject* get_image_as_numpy(int flip, PyObject* out) {
294         npy_intp dim[3];
295         unsigned char* img;
296         PyObject* npimg;
297         dim[0] = self->H;
298         dim[1] = self->W;
299         dim[2] = 4;
300         img = cairo_image_surface_get_data(self->target);
301         // Possible memory problems here...
302         if (out == Py_None || out == NULL) {
303             // rgba
304             npimg = PyArray_EMPTY(3, dim, NPY_UBYTE, 0);
305             if (!npimg) {
306                 PyErr_SetString(PyExc_ValueError, "Failed to allocate numpy array in plotstuff.get_image_as_numpy");
307                 return NULL;
308             }
309             assert(npimg);
310         } else {
311             npimg = out;
312         }
313         if (flip) {
314             cairoutils_argb32_to_rgba_flip(img, PyArray_DATA((PyArrayObject*)npimg), self->W, self->H);
315         } else {
316             cairoutils_argb32_to_rgba_2(img, PyArray_DATA((PyArrayObject*)npimg), self->W, self->H);
317         }
318         return npimg;
319     }
320 
321     PyObject* get_image_as_numpy_view() {
322         unsigned char* img;
323         npy_intp dim[3];
324         PyArray_Descr* dtype = PyArray_DescrFromType(NPY_UBYTE);
325         dim[0] = self->H;
326         dim[1] = self->W;
327         dim[2] = 4;
328         img = cairo_image_surface_get_data(self->target);
329         if (!img) {
330             PyErr_SetString(PyExc_ValueError, "Cairo image survey data is NULL in plotstuff.get_image_as_numpy_view");
331             return NULL;
332         }
333         Py_INCREF(dtype);
334         PyObject* npimg = PyArray_NewFromDescr(&PyArray_Type, dtype, 3, dim, NULL,
335                                                img, 0, NULL);
336         return npimg;
337     }
338 
339     int set_image_from_numpy(PyObject* py_img, int flip) {
340         unsigned char* img;
341         unsigned char* inimg;
342         PyArray_Descr* dtype = PyArray_DescrFromType(NPY_UBYTE);
343         int req = NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED;
344         PyArrayObject *np_img=NULL;
345         Py_INCREF(dtype);
346         np_img = (PyArrayObject*)PyArray_FromAny(py_img, dtype, 3, 3, req, NULL);
347         if ((PyArray_DIM(np_img, 0) != self->H) ||
348             (PyArray_DIM(np_img, 1) != self->W) ||
349             (PyArray_DIM(np_img, 2) != 4)) {
350             PyErr_SetString(PyExc_ValueError, "Expected image with shape (H, W, 4)");
351             return -1;
352         }
353         if (!np_img) {
354             PyErr_SetString(PyExc_ValueError, "img wasn't the type expected");
355             Py_DECREF(dtype);
356             return -1;
357         }
358         inimg = PyArray_DATA(np_img);
359         img = cairo_image_surface_get_data(self->target);
360         if (flip) {
361             cairoutils_rgba_to_argb32_flip(inimg, img, self->W, self->H);
362         } else {
363             cairoutils_rgba_to_argb32_2(inimg, img, self->W, self->H);
364         }
365         Py_DECREF(np_img);
366         Py_DECREF(dtype);
367         return 0;
368     }
369 
370     int set_wcs_file(const char* fn, int ext) {
371         return plotstuff_set_wcs_file(self, fn, ext);
372     }
373 
374     int set_size_from_wcs() {
375         return plotstuff_set_size_wcs(self);
376     }
377 
378     int count_ra_labels() {
379       return plot_grid_count_ra_labels(self);
380     }
381     int count_dec_labels() {
382       return plot_grid_count_dec_labels(self);
383     }
384 
385     void loginit(int level) {
386         log_init(level);
387     }
388 }
389 
390 %extend annotation_args {
391     void add_target(double ra, double dec, const char* name) {
392         plot_annotations_add_target(self, ra, dec, name);
393     }
394     void add_named_target(const char* name) {
395         plot_annotations_add_named_target(self, name);
396     }
397     void clear_targets() {
398         plot_annotations_clear_targets(self);
399     }
400 }
401 
402 %extend plotgrid_args {
403     int set_formats(const char* raformat, const char* decformat) {
404         return plot_grid_set_formats(self, raformat, decformat);
405     }
406 }
407 
408 %extend plotoutline_args {
409     int set_wcs_file(const char* fn, int ext) {
410         return plot_outline_set_wcs_file(self, fn, ext);
411     }
412     int set_wcs_size(int W, int H) {
413         return plot_outline_set_wcs_size(self, W, H);
414     }
415     int set_wcs(const tan_t* wcs) {
416         return plot_outline_set_tan_wcs(self, wcs);
417     }
418 }
419 %pythoncode %{
420     def plotoutline_setattr(self, name, val):
421         if name == 'wcs_file':
422             if type(val) is tuple:
423                 (fn,ext) = val
424             else:
425                 fn = val
426                 ext = 0
427             plot_outline_set_wcs_file(self, fn, ext)
428             return
429         self.__swig__setattr__(name, val)
430 
431     plotoutline_args.__swig__setattr__ = plotoutline_args.__setattr__
432     plotoutline_args.__setattr__ = plotoutline_setattr
433 %}
434 
435 %extend plotxy_args {
436     void set_filename(const char* fn) {
437       plot_xy_set_filename(self, fn);
438     }
439 }
440 
441 %extend plotradec_args {
442     void set_filename(const char* fn) {
443       plot_radec_set_filename(self, fn);
444     }
445 }
446 
447 %extend plotimage_args {
448     int _set_image_from_numpy(PyObject* arr) {
449         // Pirate array
450         PyArrayObject* yarr;
451         int hasalpha = 0;
452         int i, N;
453         unsigned char* src;
454 
455         // MAGIC 3: min_depth and max_depth (number of dims)
456         yarr = (PyArrayObject*)PyArray_FROMANY(arr, NPY_UBYTE, 3, 3,
457                                                NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED);
458         if (!yarr) {
459             PyErr_SetString(PyExc_ValueError, "Array must be 3-dimensional ubyte");
460             return -1;
461         }
462 
463         switch (PyArray_DIM(yarr, 2)) {
464             // RGB
465         case 3:
466             hasalpha = 0;
467             break;
468             // RGBA
469         case 4:
470             hasalpha = 1;
471             break;
472         default:
473             PyErr_SetString(PyExc_ValueError, "Array must be RGB or RGBA");
474             return -1;
475         }
476         src = PyArray_DATA(yarr);
477         if (self->img) {
478             free(self->img);
479         }
480         self->H = (int)PyArray_DIM(yarr, 0);
481         self->W = (int)PyArray_DIM(yarr, 1);
482         //printf("Allocating new %i x %i image\n", self->W, self->H);
483         self->img = malloc(self->W * self->H * 4);
484         N = self->W * self->H;
485         for (i=0; i<N; i++) {
486             if (hasalpha)
487                 memcpy(self->img + 4*i, src + 4*i, 4);
488             else {
489                 memcpy(self->img + 4*i, src + 3*i, 3);
490                 self->img[4*i+3] = 255;
491             }
492         }
493         Py_DECREF(yarr);
494         return 0;
495     }
496 
497     int set_wcs_file(const char* fn, int ext) {
498         return plot_image_set_wcs(self, fn, ext);
499     }
500     int set_file(const char* fn) {
501         return plot_image_set_filename(self, fn);
502     }
503     void set_rgbscale(double r, double g, double b) {
504         self->rgbscale[0] = r;
505         self->rgbscale[1] = g;
506         self->rgbscale[2] = b;
507     }
508     int get_image_width() {
509         int W;
510         if (plot_image_getsize(self, &W, NULL)) {
511             return -1;
512         }
513         return W;
514     }
515     int get_image_height() {
516         int H;
517         if (plot_image_getsize(self, NULL, &H)) {
518             return -1;
519         }
520         return H;
521     }
522 }
523 
524 %pythoncode %{
525     def plotimage_set_image_from_numpy(self, img):
526         rtn = self._set_image_from_numpy(img)
527         if rtn:
528             raise RuntimeError('set_image_from_numpy() failed')
529     plotimage_args.set_image_from_numpy = plotimage_set_image_from_numpy
530 %}
531 
532 %extend plotindex_args {
533     int add_file(const char* fn) {
534         return plot_index_add_file(self, fn);
535     }
536 }
537