1 /*
2  Author: Michael Droettboom
3          mdroe@stsci.edu
4 */
5 
6 #define NO_IMPORT_ARRAY
7 
8 #include "astropy_wcs/distortion_wrap.h"
9 #include "astropy_wcs/docstrings.h"
10 
11 #include <structmember.h> /* From Python */
12 
13 static int
PyDistLookup_traverse(PyDistLookup * self,visitproc visit,void * arg)14 PyDistLookup_traverse(
15     PyDistLookup* self,
16     visitproc visit,
17     void* arg) {
18 
19   Py_VISIT(self->py_data);
20 
21   return 0;
22 }
23 
24 static int
PyDistLookup_clear(PyDistLookup * self)25 PyDistLookup_clear(
26     PyDistLookup* self) {
27 
28   Py_CLEAR(self->py_data);
29 
30   return 0;
31 }
32 
33 static void
PyDistLookup_dealloc(PyDistLookup * self)34 PyDistLookup_dealloc(
35     PyDistLookup* self) {
36 
37   PyObject_GC_UnTrack(self);
38   distortion_lookup_t_free(&self->x);
39   Py_XDECREF(self->py_data);
40   Py_TYPE(self)->tp_free((PyObject*)self);
41 }
42 
43 /*@null@*/ static PyObject *
PyDistLookup_new(PyTypeObject * type,PyObject * args,PyObject * kwds)44 PyDistLookup_new(
45     PyTypeObject* type,
46     /*@unused@*/ PyObject* args,
47     /*@unused@*/ PyObject* kwds) {
48 
49   PyDistLookup* self;
50 
51   self = (PyDistLookup*)type->tp_alloc(type, 0);
52   if (self != NULL) {
53     if (distortion_lookup_t_init(&self->x)) {
54       return NULL;
55     }
56     self->py_data = NULL;
57   }
58   return (PyObject*)self;
59 }
60 
61 static int
PyDistLookup_init(PyDistLookup * self,PyObject * args,PyObject * kwds)62 PyDistLookup_init(
63     PyDistLookup* self,
64     PyObject* args,
65     /*@unused@*/ PyObject* kwds) {
66 
67   PyObject* py_array_obj = NULL;
68   PyArrayObject* array_obj = NULL;
69 
70   if (!PyArg_ParseTuple(args, "O(dd)(dd)(dd):DistortionLookupTable.__init__",
71                         &py_array_obj,
72                         &(self->x.crpix[0]), &(self->x.crpix[1]),
73                         &(self->x.crval[0]), &(self->x.crval[1]),
74                         &(self->x.cdelt[0]), &(self->x.cdelt[1]))) {
75     return -1;
76   }
77 
78   array_obj = (PyArrayObject*)PyArray_ContiguousFromAny(py_array_obj, NPY_FLOAT32, 2, 2);
79   if (array_obj == NULL) {
80     return -1;
81   }
82 
83   self->py_data = array_obj;
84   self->x.naxis[0] = (unsigned int)PyArray_DIM(array_obj, 1);
85   self->x.naxis[1] = (unsigned int)PyArray_DIM(array_obj, 0);
86   self->x.data = (float *)PyArray_DATA(array_obj);
87 
88   return 0;
89 }
90 
91 static PyObject*
PyDistLookup_get_cdelt(PyDistLookup * self,void * closure)92 PyDistLookup_get_cdelt(
93     PyDistLookup* self,
94     /*@unused@*/ void* closure) {
95 
96   Py_ssize_t naxis = 2;
97 
98   return get_double_array("cdelt", self->x.cdelt, 1, &naxis, (PyObject*)self);
99 }
100 
101 static int
PyDistLookup_set_cdelt(PyDistLookup * self,PyObject * value,void * closure)102 PyDistLookup_set_cdelt(
103     PyDistLookup* self,
104     PyObject* value,
105     /*@unused@*/ void* closure) {
106 
107   npy_intp naxis = 2;
108 
109   return set_double_array("cdelt", value, 1, &naxis, self->x.cdelt);
110 }
111 
112 static PyObject*
PyDistLookup_get_crpix(PyDistLookup * self,void * closure)113 PyDistLookup_get_crpix(
114     PyDistLookup* self,
115     /*@unused@*/ void* closure) {
116 
117   Py_ssize_t naxis = 2;
118 
119   return get_double_array("crpix", self->x.crpix, 1, &naxis, (PyObject*)self);
120 }
121 
122 static int
PyDistLookup_set_crpix(PyDistLookup * self,PyObject * value,void * closure)123 PyDistLookup_set_crpix(
124     PyDistLookup* self,
125     PyObject* value,
126     /*@unused@*/ void* closure) {
127 
128   npy_intp naxis = 2;
129 
130   return set_double_array("crpix", value, 1, &naxis, self->x.crpix);
131 }
132 
133 static PyObject*
PyDistLookup_get_crval(PyDistLookup * self,void * closure)134 PyDistLookup_get_crval(
135     PyDistLookup* self,
136     /*@unused@*/ void* closure) {
137 
138   Py_ssize_t naxis = 2;
139 
140   return get_double_array("crval", self->x.crval, 1, &naxis, (PyObject*)self);
141 }
142 
143 static int
PyDistLookup_set_crval(PyDistLookup * self,PyObject * value,void * closure)144 PyDistLookup_set_crval(
145     PyDistLookup* self,
146     PyObject* value,
147     /*@unused@*/ void* closure) {
148 
149   npy_intp naxis = 2;
150 
151   return set_double_array("crval", value, 1, &naxis, self->x.crval);
152 }
153 
154 /*@shared@*/ static PyObject*
PyDistLookup_get_data(PyDistLookup * self,void * closure)155 PyDistLookup_get_data(
156     PyDistLookup* self,
157     /*@unused@*/ void* closure) {
158 
159   if (self->py_data == NULL) {
160     Py_INCREF(Py_None);
161     return Py_None;
162   } else {
163     Py_INCREF(self->py_data);
164     return (PyObject*)self->py_data;
165   }
166 }
167 
168 static int
PyDistLookup_set_data(PyDistLookup * self,PyObject * value,void * closure)169 PyDistLookup_set_data(
170     PyDistLookup* self,
171     PyObject* value,
172     /*@unused@*/ void* closure) {
173 
174   PyArrayObject* value_array = NULL;
175 
176   if (value == NULL) {
177     Py_CLEAR(self->py_data);
178     self->x.data = NULL;
179     return 0;
180   }
181 
182   value_array = (PyArrayObject*)PyArray_ContiguousFromAny(value, NPY_FLOAT32, 2, 2);
183 
184   if (value_array == NULL) {
185     return -1;
186   }
187 
188   Py_XDECREF(self->py_data);
189 
190   self->py_data = value_array;
191   self->x.naxis[0] = (unsigned int)PyArray_DIM(value_array, 1);
192   self->x.naxis[1] = (unsigned int)PyArray_DIM(value_array, 0);
193   self->x.data = (float *)PyArray_DATA(value_array);
194 
195   return 0;
196 }
197 
198 /*@null@*/ static PyObject*
PyDistLookup_get_offset(PyDistLookup * self,PyObject * args,PyObject * kwds)199 PyDistLookup_get_offset(
200     PyDistLookup* self,
201     PyObject* args,
202     /*@unused@*/ PyObject* kwds) {
203 
204   double coord[NAXES];
205   double result;
206 
207   if (self->x.data == NULL) {
208     PyErr_SetString(PyExc_RuntimeError,
209                     "No data has been set for the lookup table");
210     return NULL;
211   }
212 
213   if (!PyArg_ParseTuple(args, "dd:get_offset", &coord[0], &coord[1])) {
214     return NULL;
215   }
216 
217   result = get_distortion_offset(&self->x, coord);
218   return PyFloat_FromDouble(result);
219 }
220 
221 static PyObject*
PyDistLookup___copy__(PyDistLookup * self,PyObject * args,PyObject * kwds)222 PyDistLookup___copy__(
223     PyDistLookup* self,
224     /*@unused@*/ PyObject* args,
225     /*@unused@*/ PyObject* kwds) {
226 
227   PyDistLookup* copy = NULL;
228   int           i    = 0;
229 
230   copy = (PyDistLookup*)PyDistLookup_new(&PyDistLookupType, NULL, NULL);
231   if (copy == NULL) {
232     return NULL;
233   }
234 
235   for (i = 0; i < 2; ++i) {
236     copy->x.naxis[i] = self->x.naxis[i];
237     copy->x.crpix[i] = self->x.crpix[i];
238     copy->x.crval[i] = self->x.crval[i];
239     copy->x.cdelt[i] = self->x.cdelt[i];
240   }
241 
242   if (self->py_data) {
243     PyDistLookup_set_data(copy, (PyObject*)self->py_data, NULL);
244   }
245 
246   return (PyObject*)copy;
247 }
248 
249 static PyObject*
PyDistLookup___deepcopy__(PyDistLookup * self,PyObject * memo,PyObject * kwds)250 PyDistLookup___deepcopy__(
251     PyDistLookup* self,
252     PyObject* memo,
253     /*@unused@*/ PyObject* kwds) {
254 
255   PyDistLookup* copy;
256   PyObject*     obj_copy;
257   int           i = 0;
258 
259   copy = (PyDistLookup*)PyDistLookup_new(&PyDistLookupType, NULL, NULL);
260   if (copy == NULL) {
261     return NULL;
262   }
263 
264   for (i = 0; i < 2; ++i) {
265     copy->x.naxis[i] = self->x.naxis[i];
266     copy->x.crpix[i] = self->x.crpix[i];
267     copy->x.crval[i] = self->x.crval[i];
268     copy->x.cdelt[i] = self->x.cdelt[i];
269   }
270 
271   if (self->py_data) {
272     obj_copy = get_deepcopy((PyObject*)self->py_data, memo);
273     if (obj_copy == NULL) {
274       Py_DECREF(copy);
275       return NULL;
276     }
277     PyDistLookup_set_data(copy, (PyObject*)obj_copy, NULL);
278     Py_DECREF(obj_copy);
279   }
280 
281   return (PyObject*)copy;
282 }
283 
284 
285 static PyGetSetDef PyDistLookup_getset[] = {
286   {"cdelt", (getter)PyDistLookup_get_cdelt, (setter)PyDistLookup_set_cdelt, (char *)doc_cdelt},
287   {"crpix", (getter)PyDistLookup_get_crpix, (setter)PyDistLookup_set_crpix, (char *)doc_crpix},
288   {"crval", (getter)PyDistLookup_get_crval, (setter)PyDistLookup_set_crval, (char *)doc_crval},
289   {"data",  (getter)PyDistLookup_get_data,  (setter)PyDistLookup_set_data,  (char *)doc_data},
290   {NULL}
291 };
292 
293 static PyMethodDef PyDistLookup_methods[] = {
294   {"__copy__", (PyCFunction)PyDistLookup___copy__, METH_NOARGS, NULL},
295   {"__deepcopy__", (PyCFunction)PyDistLookup___deepcopy__, METH_O, NULL},
296   {"get_offset", (PyCFunction)PyDistLookup_get_offset, METH_VARARGS, doc_get_offset},
297   {NULL}
298 };
299 
300 PyTypeObject PyDistLookupType = {
301   PyVarObject_HEAD_INIT(NULL, 0)
302   "astropy.wcs.DistortionLookupTable",  /*tp_name*/
303   sizeof(PyDistLookup),         /*tp_basicsize*/
304   0,                            /*tp_itemsize*/
305   (destructor)PyDistLookup_dealloc, /*tp_dealloc*/
306   0,                            /*tp_print*/
307   0,                            /*tp_getattr*/
308   0,                            /*tp_setattr*/
309   0,                            /*tp_compare*/
310   0,                            /*tp_repr*/
311   0,                            /*tp_as_number*/
312   0,                            /*tp_as_sequence*/
313   0,                            /*tp_as_mapping*/
314   0,                            /*tp_hash */
315   0,                            /*tp_call*/
316   0,                            /*tp_str*/
317   0,                            /*tp_getattro*/
318   0,                            /*tp_setattro*/
319   0,                            /*tp_as_buffer*/
320   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
321   doc_DistortionLookupTable,    /* tp_doc */
322   (traverseproc)PyDistLookup_traverse, /* tp_traverse */
323   (inquiry)PyDistLookup_clear,  /* tp_clear */
324   0,                            /* tp_richcompare */
325   0,                            /* tp_weaklistoffset */
326   0,                            /* tp_iter */
327   0,                            /* tp_iternext */
328   PyDistLookup_methods,         /* tp_methods */
329   0,                            /* tp_members */
330   PyDistLookup_getset,          /* tp_getset */
331   0,                            /* tp_base */
332   0,                            /* tp_dict */
333   0,                            /* tp_descr_get */
334   0,                            /* tp_descr_set */
335   0,                            /* tp_dictoffset */
336   (initproc)PyDistLookup_init,  /* tp_init */
337   0,                            /* tp_alloc */
338   PyDistLookup_new,             /* tp_new */
339 };
340 
_setup_distortion_type(PyObject * m)341 int _setup_distortion_type(
342     PyObject* m) {
343 
344   if (PyType_Ready(&PyDistLookupType) < 0) {
345     return -1;
346   }
347 
348   Py_INCREF(&PyDistLookupType);
349   return PyModule_AddObject(m, "DistortionLookupTable", (PyObject *)&PyDistLookupType);
350 }
351