drizzle 2.0.1__cp312-cp312-macosx_10_13_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of drizzle might be problematic. Click here for more details.

@@ -0,0 +1,238 @@
1
+ import numpy as np
2
+ import pytest
3
+ from numpy.testing import assert_almost_equal, assert_equal
4
+
5
+ from drizzle.utils import (
6
+ _estimate_pixel_scale,
7
+ calc_pixmap,
8
+ decode_context,
9
+ estimate_pixel_scale_ratio,
10
+ )
11
+
12
+ from .helpers import wcs_from_file
13
+
14
+
15
+ def test_map_rectangular():
16
+ """
17
+ Make sure the initial index array has correct values
18
+ """
19
+ naxis1 = 1000
20
+ naxis2 = 10
21
+
22
+ pixmap = np.indices((naxis1, naxis2), dtype='float32')
23
+ pixmap = pixmap.transpose()
24
+
25
+ assert_equal(pixmap[5, 500], (500, 5))
26
+
27
+
28
+ @pytest.mark.parametrize(
29
+ "wcs_type", ["fits", "gwcs"]
30
+ )
31
+ def test_map_to_self(wcs_type):
32
+ """
33
+ Map a pixel array to itself. Should return the same array.
34
+ """
35
+ input_wcs = wcs_from_file("j8bt06nyq_sip_flt.fits", ext=1, wcs_type=wcs_type)
36
+ shape = input_wcs.array_shape
37
+
38
+ ok_pixmap = np.indices(shape, dtype='float64')
39
+ ok_pixmap = ok_pixmap.transpose()
40
+
41
+ pixmap = calc_pixmap(input_wcs, input_wcs)
42
+
43
+ # Got x-y transpose right
44
+ assert_equal(pixmap.shape, ok_pixmap.shape)
45
+
46
+ # Mapping an array to itself
47
+ assert_almost_equal(pixmap, ok_pixmap, decimal=5)
48
+
49
+ # user-provided shape
50
+ pixmap = calc_pixmap(input_wcs, input_wcs, (12, 34))
51
+ assert_equal(pixmap.shape, (12, 34, 2))
52
+
53
+ # Check that an exception is raised for WCS without pixel_shape and
54
+ # bounding_box:
55
+ input_wcs.pixel_shape = None
56
+ input_wcs.bounding_box = None
57
+ with pytest.raises(ValueError):
58
+ calc_pixmap(input_wcs, input_wcs)
59
+
60
+ # user-provided shape when array_shape is not set:
61
+ pixmap = calc_pixmap(input_wcs, input_wcs, (12, 34))
62
+ assert_equal(pixmap.shape, (12, 34, 2))
63
+
64
+ # from bounding box:
65
+ input_wcs.bounding_box = ((5.3, 33.5), (2.8, 11.5))
66
+ pixmap = calc_pixmap(input_wcs, input_wcs)
67
+ assert_equal(pixmap.shape, (12, 34, 2))
68
+
69
+ # from bounding box and pixel_shape (the later takes precedence):
70
+ input_wcs.array_shape = shape
71
+ pixmap = calc_pixmap(input_wcs, input_wcs)
72
+ assert_equal(pixmap.shape, ok_pixmap.shape)
73
+
74
+
75
+ @pytest.mark.parametrize(
76
+ "wcs_type", ["fits", "gwcs"]
77
+ )
78
+ def test_translated_map(wcs_type):
79
+ """
80
+ Map a pixel array to at translated array.
81
+ """
82
+ first_wcs = wcs_from_file(
83
+ "j8bt06nyq_sip_flt.fits",
84
+ ext=1,
85
+ wcs_type=wcs_type
86
+ )
87
+ second_wcs = wcs_from_file(
88
+ "j8bt06nyq_sip_flt.fits",
89
+ ext=1,
90
+ crpix_shift=(-2, -2), # shift loaded WCS by adding this to CRPIX
91
+ wcs_type=wcs_type
92
+ )
93
+
94
+ ok_pixmap = np.indices(first_wcs.array_shape, dtype='float32') - 2.0
95
+ ok_pixmap = ok_pixmap.transpose()
96
+
97
+ pixmap = calc_pixmap(first_wcs, second_wcs)
98
+
99
+ # Got x-y transpose right
100
+ assert_equal(pixmap.shape, ok_pixmap.shape)
101
+ # Mapping an array to a translated array
102
+ assert_almost_equal(pixmap[2:, 2:], ok_pixmap[2:, 2:], decimal=5)
103
+
104
+
105
+ def test_disable_gwcs_bbox():
106
+ """
107
+ Map a pixel array to a translated version ofitself.
108
+ """
109
+ first_wcs = wcs_from_file(
110
+ "j8bt06nyq_sip_flt.fits",
111
+ ext=1,
112
+ wcs_type="gwcs"
113
+ )
114
+ second_wcs = wcs_from_file(
115
+ "j8bt06nyq_sip_flt.fits",
116
+ ext=1,
117
+ crpix_shift=(-2, -2), # shift loaded WCS by adding this to CRPIX
118
+ wcs_type="gwcs"
119
+ )
120
+
121
+ ok_pixmap = np.indices(first_wcs.array_shape, dtype='float64') - 2.0
122
+ ok_pixmap = ok_pixmap.transpose()
123
+
124
+ # Mapping an array to a translated array
125
+
126
+ # disable both bounding boxes:
127
+ pixmap = calc_pixmap(first_wcs, second_wcs, disable_bbox="both")
128
+ assert_almost_equal(pixmap[2:, 2:], ok_pixmap[2:, 2:], decimal=5)
129
+ assert np.all(np.isfinite(pixmap[:2, :2]))
130
+ assert np.all(np.isfinite(pixmap[-2:, -2:]))
131
+ # check bbox was restored
132
+ assert first_wcs.bounding_box is not None
133
+ assert second_wcs.bounding_box is not None
134
+
135
+ # disable "from" bounding box:
136
+ pixmap = calc_pixmap(second_wcs, first_wcs, disable_bbox="from")
137
+ assert_almost_equal(pixmap[:-2, :-2], ok_pixmap[:-2, :-2] + 4.0, decimal=5)
138
+ assert np.all(np.logical_not(np.isfinite(pixmap[-2:, -2:])))
139
+ # check bbox was restored
140
+ assert first_wcs.bounding_box is not None
141
+ assert second_wcs.bounding_box is not None
142
+
143
+ # disable "to" bounding boxes:
144
+ pixmap = calc_pixmap(first_wcs, second_wcs, disable_bbox="to")
145
+ assert_almost_equal(pixmap[2:, 2:], ok_pixmap[2:, 2:], decimal=5)
146
+ assert np.all(np.isfinite(pixmap[:2, :2]))
147
+ assert np.all(pixmap[:2, :2] < 0.0)
148
+ assert np.all(np.isfinite(pixmap[-2:, -2:]))
149
+ # check bbox was restored
150
+ assert first_wcs.bounding_box is not None
151
+ assert second_wcs.bounding_box is not None
152
+
153
+ # enable all bounding boxes:
154
+ pixmap = calc_pixmap(first_wcs, second_wcs, disable_bbox="none")
155
+ assert_almost_equal(pixmap[2:, 2:], ok_pixmap[2:, 2:], decimal=5)
156
+ assert np.all(np.logical_not(np.isfinite(pixmap[:2, :2])))
157
+ # check bbox was restored
158
+ assert first_wcs.bounding_box is not None
159
+ assert second_wcs.bounding_box is not None
160
+
161
+
162
+ def test_estimate_pixel_scale_ratio():
163
+ w = wcs_from_file("j8bt06nyq_flt.fits", ext=1)
164
+ pscale = estimate_pixel_scale_ratio(w, w, w.wcs.crpix, (0, 0))
165
+ assert abs(pscale - 0.9999999916964737) < 1.0e-9
166
+
167
+
168
+ def test_estimate_pixel_scale_no_refpix():
169
+ # create a WCS without higher order (polynomial) distortions:
170
+ w = wcs_from_file("j8bt06nyq_sip_flt.fits", ext=1)
171
+ w.sip = None
172
+ w.det2im1 = None
173
+ w.det2im2 = None
174
+ w.cpdis1 = None
175
+ w.cpdis2 = None
176
+ pixel_shape = w.pixel_shape[:]
177
+
178
+ ref_pscale = _estimate_pixel_scale(w, w.wcs.crpix)
179
+
180
+ if hasattr(w, 'bounding_box'):
181
+ del w.bounding_box
182
+ pscale1 = _estimate_pixel_scale(w, None)
183
+ assert np.allclose(ref_pscale, pscale1, atol=0.0, rtol=1.0e-8)
184
+
185
+ w.bounding_box = None
186
+ w.pixel_shape = None
187
+ pscale2 = _estimate_pixel_scale(w, None)
188
+ assert np.allclose(pscale1, pscale2, atol=0.0, rtol=1.0e-8)
189
+
190
+ w.pixel_shape = pixel_shape
191
+ pscale3 = _estimate_pixel_scale(w, None)
192
+ assert np.allclose(pscale1, pscale3, atol=0.0, rtol=1.0e-14)
193
+
194
+ w.bounding_box = ((-0.5, pixel_shape[0] - 0.5), (-0.5, pixel_shape[1] - 0.5))
195
+ pscale4 = _estimate_pixel_scale(w, None)
196
+ assert np.allclose(pscale3, pscale4, atol=0.0, rtol=1.0e-8)
197
+
198
+
199
+ def test_decode_context():
200
+ ctx = np.array(
201
+ [[[0, 0, 0, 0, 0, 0],
202
+ [0, 0, 0, 36196864, 0, 0],
203
+ [0, 0, 0, 0, 0, 0],
204
+ [0, 0, 0, 0, 0, 0],
205
+ [0, 0, 537920000, 0, 0, 0]],
206
+ [[0, 0, 0, 0, 0, 0,],
207
+ [0, 0, 0, 67125536, 0, 0],
208
+ [0, 0, 0, 0, 0, 0],
209
+ [0, 0, 0, 0, 0, 0],
210
+ [0, 0, 163856, 0, 0, 0]],
211
+ [[0, 0, 0, 0, 0, 0],
212
+ [0, 0, 0, 8203, 0, 0],
213
+ [0, 0, 0, 0, 0, 0],
214
+ [0, 0, 0, 0, 0, 0],
215
+ [0, 0, 32865, 0, 0, 0]]],
216
+ dtype=np.int32
217
+ )
218
+
219
+ idx1, idx2 = decode_context(ctx, [3, 2], [1, 4])
220
+
221
+ assert sorted(idx1) == [9, 12, 14, 19, 21, 25, 37, 40, 46, 58, 64, 65, 67, 77]
222
+ assert sorted(idx2) == [9, 20, 29, 36, 47, 49, 64, 69, 70, 79]
223
+
224
+ # context array must be 3D:
225
+ with pytest.raises(ValueError):
226
+ decode_context(ctx[0], [3, 2], [1, 4])
227
+
228
+ # pixel coordinates must be integer:
229
+ with pytest.raises(ValueError):
230
+ decode_context(ctx, [3.0, 2], [1, 4])
231
+
232
+ # coordinate lists must be equal in length:
233
+ with pytest.raises(ValueError):
234
+ decode_context(ctx, [3, 2], [1, 4, 5])
235
+
236
+ # coordinate lists must be 1D:
237
+ with pytest.raises(ValueError):
238
+ decode_context(ctx, [[3, 2]], [[1, 4]])
drizzle/util.py ADDED
@@ -0,0 +1,34 @@
1
+ """
2
+ Module ``util`` has been deprecated.
3
+ """
4
+ import warnings
5
+
6
+ warnings.warn(
7
+ "Module 'drizzle.util' has been deprecated since version 2.0.0 "
8
+ "and it will be removed in a future release. "
9
+ "Please replace calls to 'util.is_blank()' with alternative "
10
+ "implementation.",
11
+ DeprecationWarning
12
+ )
13
+
14
+
15
+ def is_blank(value):
16
+ """
17
+ Determines whether or not a value is considered 'blank'.
18
+
19
+ Parameters
20
+ ----------
21
+ value : str
22
+ The value to check
23
+
24
+ Returns
25
+ -------
26
+ True or False
27
+ """
28
+ warnings.warn(
29
+ "'is_blank()' has been deprecated since version 2.0.0 "
30
+ "and it will be removed in a future release. "
31
+ "Please replace calls to 'is_blank()' with alternative implementation.",
32
+ DeprecationWarning
33
+ )
34
+ return value.strip() == ""
drizzle/utils.py ADDED
@@ -0,0 +1,285 @@
1
+ import math
2
+
3
+ import numpy as np
4
+
5
+ __all__ = ["calc_pixmap", "decode_context", "estimate_pixel_scale_ratio"]
6
+
7
+ _DEG2RAD = math.pi / 180.0
8
+
9
+
10
+ def calc_pixmap(wcs_from, wcs_to, shape=None, disable_bbox="to"):
11
+ """
12
+ Calculate a discretized on a grid mapping between the pixels of two images
13
+ using provided WCS of the original ("from") image and the destination ("to")
14
+ image.
15
+
16
+ .. note::
17
+ This function assumes that output frames of ``wcs_from`` and ``wcs_to``
18
+ WCS have the same units.
19
+
20
+ Parameters
21
+ ----------
22
+ wcs_from : wcs
23
+ A WCS object representing the coordinate system you are
24
+ converting from. This object's ``array_shape`` (or ``pixel_shape``)
25
+ property will be used to define the shape of the pixel map array.
26
+ If ``shape`` parameter is provided, it will take precedence
27
+ over this object's ``array_shape`` value.
28
+
29
+ wcs_to : wcs
30
+ A WCS object representing the coordinate system you are
31
+ converting to.
32
+
33
+ shape : tuple, None, optional
34
+ A tuple of integers indicating the shape of the output array in the
35
+ ``numpy.ndarray`` order. When provided, it takes precedence over the
36
+ ``wcs_from.array_shape`` property.
37
+
38
+ disable_bbox : {"to", "from", "both", "none"}, optional
39
+ Indicates whether to use or not to use the bounding box of either
40
+ (both) ``wcs_from`` or (and) ``wcs_to`` when computing pixel map. When
41
+ ``disable_bbox`` is "none", pixel coordinates outside of the bounding
42
+ box are set to `NaN` only if ``wcs_from`` or (and) ``wcs_to`` sets
43
+ world coordinates to NaN when input pixel coordinates are outside of
44
+ the bounding box.
45
+
46
+ Returns
47
+ -------
48
+ pixmap : numpy.ndarray
49
+ A three dimensional array representing the transformation between
50
+ the two. The last dimension is of length two and contains the x and
51
+ y coordinates of a pixel center, repectively. The other two coordinates
52
+ correspond to the two coordinates of the image the first WCS is from.
53
+
54
+ Raises
55
+ ------
56
+ ValueError
57
+ A `ValueError` is raised when output pixel map shape cannot be
58
+ determined from provided inputs.
59
+
60
+ Notes
61
+ -----
62
+ When ``shape`` is not provided and ``wcs_from.array_shape`` is not set
63
+ (i.e., it is `None`), `calc_pixmap` will attempt to determine pixel map
64
+ shape from the ``bounding_box`` property of the input ``wcs_from`` object.
65
+ If ``bounding_box`` is not available, a `ValueError` will be raised.
66
+
67
+ """
68
+ if (bbox_from := getattr(wcs_from, "bounding_box", None)) is not None:
69
+ try:
70
+ # to avoid dependency on astropy just to check whether
71
+ # the bounding box is an instance of
72
+ # modeling.bounding_box.ModelBoundingBox, we try to
73
+ # directly use and bounding_box(order='F') and if it fails,
74
+ # fall back to converting the bounding box to a tuple
75
+ # (of intervals):
76
+ bbox_from = bbox_from.bounding_box(order='F')
77
+ except AttributeError:
78
+ bbox_from = tuple(bbox_from)
79
+
80
+ if (bbox_to := getattr(wcs_to, "bounding_box", None)) is not None:
81
+ try:
82
+ # to avoid dependency on astropy just to check whether
83
+ # the bounding box is an instance of
84
+ # modeling.bounding_box.ModelBoundingBox, we try to
85
+ # directly use and bounding_box(order='F') and if it fails,
86
+ # fall back to converting the bounding box to a tuple
87
+ # (of intervals):
88
+ bbox_to = bbox_to.bounding_box(order='F')
89
+ except AttributeError:
90
+ bbox_to = tuple(bbox_to)
91
+
92
+ if shape is None:
93
+ shape = wcs_from.array_shape
94
+ if shape is None and bbox_from is not None:
95
+ if (nd := np.ndim(bbox_from)) == 1:
96
+ bbox_from = (bbox_from, )
97
+ if nd > 1:
98
+ shape = tuple(
99
+ int(math.ceil(lim[1] + 0.5)) for lim in bbox_from[::-1]
100
+ )
101
+
102
+ if shape is None:
103
+ raise ValueError(
104
+ 'The "from" WCS must have pixel_shape property set.'
105
+ )
106
+
107
+ y, x = np.indices(shape, dtype=np.float64)
108
+
109
+ # temporarily disable the bounding box for the "from" WCS:
110
+ if disable_bbox in ["from", "both"] and bbox_from is not None:
111
+ wcs_from.bounding_box = None
112
+ if disable_bbox in ["to", "both"] and bbox_to is not None:
113
+ wcs_to.bounding_box = None
114
+ try:
115
+ x, y = wcs_to.world_to_pixel_values(
116
+ *wcs_from.pixel_to_world_values(x, y)
117
+ )
118
+ finally:
119
+ if bbox_from is not None:
120
+ wcs_from.bounding_box = bbox_from
121
+ if bbox_to is not None:
122
+ wcs_to.bounding_box = bbox_to
123
+
124
+ pixmap = np.dstack([x, y])
125
+ return pixmap
126
+
127
+
128
+ def estimate_pixel_scale_ratio(wcs_from, wcs_to, refpix_from=None, refpix_to=None):
129
+ """
130
+ Compute the ratio of the pixel scale of the "to" WCS at the ``refpix_to``
131
+ position to the pixel scale of the "from" WCS at the ``refpix_from``
132
+ position. Pixel scale ratio,
133
+ when requested, is computed near the centers of the bounding box
134
+ (a property of the WCS object) or near ``refpix_*`` coordinates
135
+ if supplied.
136
+
137
+ Pixel scale is estimated as the square root of pixel's area, i.e.,
138
+ pixels are assumed to have a square shape at the reference
139
+ pixel position. If input reference pixel position for a WCS is `None`,
140
+ it will be taken as the center of the bounding box
141
+ if ``wcs_*`` has a bounding box defined, or as the center of the box
142
+ defined by the ``pixel_shape`` attribute of the input WCS if
143
+ ``pixel_shape`` is defined (not `None`), or at pixel coordinates
144
+ ``(0, 0)``.
145
+
146
+ Parameters
147
+ ----------
148
+ wcs_from : wcs
149
+ A WCS object representing the coordinate system you are
150
+ converting from. This object *must* have ``pixel_shape`` property
151
+ defined.
152
+
153
+ wcs_to : wcs
154
+ A WCS object representing the coordinate system you are
155
+ converting to.
156
+
157
+ refpix_from : numpy.ndarray, tuple, list
158
+ Image coordinates of the reference pixel near which pixel scale should
159
+ be computed in the "from" image. In FITS WCS this could be, for example,
160
+ the value of CRPIX of the ``wcs_from`` WCS.
161
+
162
+ refpix_to : numpy.ndarray, tuple, list
163
+ Image coordinates of the reference pixel near which pixel scale should
164
+ be computed in the "to" image. In FITS WCS this could be, for example,
165
+ the value of CRPIX of the ``wcs_to`` WCS.
166
+
167
+ Returns
168
+ -------
169
+ pixel_scale_ratio : float
170
+ Estimate the ratio of "to" to "from" WCS pixel scales. This value is
171
+ returned only when ``estimate_pixel_scale_ratio`` is `True`.
172
+
173
+ """
174
+ pscale_ratio = (_estimate_pixel_scale(wcs_to, refpix_to) /
175
+ _estimate_pixel_scale(wcs_from, refpix_from))
176
+ return pscale_ratio
177
+
178
+
179
+ def _estimate_pixel_scale(wcs, refpix):
180
+ # estimate pixel scale (in rad) using approximate algorithm
181
+ # from https://trs.jpl.nasa.gov/handle/2014/40409
182
+ if refpix is None:
183
+ if hasattr(wcs, 'bounding_box') and wcs.bounding_box is not None:
184
+ refpix = np.mean(wcs.bounding_box, axis=-1)
185
+ else:
186
+ if wcs.pixel_shape:
187
+ refpix = np.array([(i - 1) // 2 for i in wcs.pixel_shape])
188
+ else:
189
+ refpix = np.zeros(wcs.pixel_n_dim)
190
+
191
+ else:
192
+ refpix = np.asarray(refpix)
193
+
194
+ l1, phi1 = wcs.pixel_to_world_values(*(refpix - 0.5))
195
+ l2, phi2 = wcs.pixel_to_world_values(*(refpix + [-0.5, 0.5]))
196
+ l3, phi3 = wcs.pixel_to_world_values(*(refpix + 0.5))
197
+ l4, phi4 = wcs.pixel_to_world_values(*(refpix + [0.5, -0.5]))
198
+ area = _DEG2RAD * abs(
199
+ 0.5 * (
200
+ (l4 - l2) * (math.sin(_DEG2RAD * phi1) - math.sin(_DEG2RAD * phi3)) +
201
+ (l1 - l3) * (math.sin(_DEG2RAD * phi2) - math.sin(_DEG2RAD * phi4))
202
+ )
203
+ )
204
+ return math.sqrt(area)
205
+
206
+
207
+ def decode_context(context, x, y):
208
+ """Get 0-based indices of input images that contributed to (resampled)
209
+ output pixel with coordinates ``x`` and ``y``.
210
+
211
+ Parameters
212
+ ----------
213
+ context: numpy.ndarray
214
+ A 3D `~numpy.ndarray` of integral data type.
215
+
216
+ x: int, list of integers, numpy.ndarray of integers
217
+ X-coordinate of pixels to decode (3rd index into the ``context`` array)
218
+
219
+ y: int, list of integers, numpy.ndarray of integers
220
+ Y-coordinate of pixels to decode (2nd index into the ``context`` array)
221
+
222
+ Returns
223
+ -------
224
+ A list of `numpy.ndarray` objects each containing indices of input images
225
+ that have contributed to an output pixel with coordinates ``x`` and ``y``.
226
+ The length of returned list is equal to the number of input coordinate
227
+ arrays ``x`` and ``y``.
228
+
229
+ Examples
230
+ --------
231
+ An example context array for an output image of array shape ``(5, 6)``
232
+ obtained by resampling 80 input images.
233
+
234
+ >>> import numpy as np
235
+ >>> from drizzle.utils import decode_context
236
+ >>> ctx = np.array(
237
+ ... [[[0, 0, 0, 0, 0, 0],
238
+ ... [0, 0, 0, 36196864, 0, 0],
239
+ ... [0, 0, 0, 0, 0, 0],
240
+ ... [0, 0, 0, 0, 0, 0],
241
+ ... [0, 0, 537920000, 0, 0, 0]],
242
+ ... [[0, 0, 0, 0, 0, 0,],
243
+ ... [0, 0, 0, 67125536, 0, 0],
244
+ ... [0, 0, 0, 0, 0, 0],
245
+ ... [0, 0, 0, 0, 0, 0],
246
+ ... [0, 0, 163856, 0, 0, 0]],
247
+ ... [[0, 0, 0, 0, 0, 0],
248
+ ... [0, 0, 0, 8203, 0, 0],
249
+ ... [0, 0, 0, 0, 0, 0],
250
+ ... [0, 0, 0, 0, 0, 0],
251
+ ... [0, 0, 32865, 0, 0, 0]]],
252
+ ... dtype=np.int32
253
+ ... )
254
+ >>> decode_context(ctx, [3, 2], [1, 4])
255
+ [array([ 9, 12, 14, 19, 21, 25, 37, 40, 46, 58, 64, 65, 67, 77]),
256
+ array([ 9, 20, 29, 36, 47, 49, 64, 69, 70, 79])]
257
+
258
+ """
259
+ if context.ndim != 3:
260
+ raise ValueError("'context' must be a 3D array.")
261
+
262
+ x = np.atleast_1d(x)
263
+ y = np.atleast_1d(y)
264
+
265
+ if x.size != y.size:
266
+ raise ValueError("Coordinate arrays must have equal length.")
267
+
268
+ if x.ndim != 1:
269
+ raise ValueError("Coordinates must be scalars or 1D arrays.")
270
+
271
+ if not (np.issubdtype(x.dtype, np.integer) and
272
+ np.issubdtype(y.dtype, np.integer)):
273
+ raise ValueError('Pixel coordinates must be integer values')
274
+
275
+ nbits = 8 * context.dtype.itemsize
276
+ one = np.array(1, context.dtype)
277
+ flags = np.array([one << i for i in range(nbits)])
278
+
279
+ idx = []
280
+ for xi, yi in zip(x, y):
281
+ idx.append(
282
+ np.flatnonzero(np.bitwise_and.outer(context[:, yi, xi], flags))
283
+ )
284
+
285
+ return idx
@@ -0,0 +1,31 @@
1
+ Copyright (C) 2011,2014 Association of Universities for Research in
2
+ Astronomy (AURA)
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ 1. Redistributions of source code must retain the above
9
+ copyright notice, this list of conditions and the following
10
+ disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above
13
+ copyright notice, this list of conditions and the following
14
+ disclaimer in the documentation and/or other materials
15
+ provided with the distribution.
16
+
17
+ 3. The name of AURA and its representatives may not be used to
18
+ endorse or promote products derived from this software without
19
+ specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR
22
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
+ ARE DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT,
25
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31
+ OF THE POSSIBILITY OF SUCH DAMAGE.