Skip to content

Coordinates¤

cart2polar

dLux.utils.coordinates.cart2polar(coordinates) ¤

Converts the input (x, y) Cartesian coordinates into (r, phi) polar coordinates.

Parameters:

Name Type Description Default
coordinates Array

The (x, y) Cartesian coordinates to be converted into polar coordinates.

required

Returns:

Name Type Description
coordinates Array

The input Cartesian coordinates converted into (r, phi) polar coordinates.

Source code in dLux/utils/coordinates.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def cart2polar(coordinates: Array) -> Array:
    """
    Converts the input (x, y) Cartesian coordinates into (r, phi) polar
    coordinates.

    Parameters
    ----------
    coordinates : Array
        The (x, y) Cartesian coordinates to be converted into polar
        coordinates.

    Returns
    -------
    coordinates : Array
        The input Cartesian coordinates converted into (r, phi) polar
        coordinates.
    """
    x, y = coordinates
    return np.array([np.hypot(x, y), np.arctan2(y, x)])
polar2cart

dLux.utils.coordinates.polar2cart(coordinates) ¤

Converts the input (r, phi) polar coordinates into (x, y) Cartesian coordinates.

Parameters:

Name Type Description Default
coordinates Array

The (r, phi) polar coordinates to be converted into Cartesian coordinates.

required

Returns:

Name Type Description
coordinates Array

The input polar coordinates converted into (x, y) Cartesian coordinates.

Source code in dLux/utils/coordinates.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
def polar2cart(coordinates: Array) -> Array:
    """
    Converts the input (r, phi) polar coordinates into (x, y) Cartesian
    coordinates.

    Parameters
    ----------
    coordinates : Array
        The (r, phi) polar coordinates to be converted into Cartesian
        coordinates.

    Returns
    -------
    coordinates : Array
        The input polar coordinates converted into (x, y) Cartesian
        coordinates.
    """
    r, phi = coordinates
    return np.array([r * np.cos(phi), r * np.sin(phi)])
pixel_coords

dLux.utils.coordinates.pixel_coords(npixels, diameter=None, radius=None, pixel_scale=None, polar=False, fft_style=False) ¤

Returns a paraxial set of 2d coordinates for each pixel center.

Parameters:

Name Type Description Default
npixels int

The output size of the coordinates array to generate.

required
diameter float = None

The diameter of the coordinates array to generate.

None
radius float = None

The radius of the coordinates array to generate.

None
pixel_scale float = None

The pixel scale of the coordinates array to generate.

None
polar bool = False

Output the coordinates in polar (r, phi) coordinates.

False
fft_style bool = False

If True, use FFT-style centering. For even npixels this produces integer centered coordinates. For odd npixels this is identical to the default.

False

Returns:

Name Type Description
coordinates Array

The array of pixel center coordinates.

Source code in dLux/utils/coordinates.py
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
def pixel_coords(
    npixels: int,
    diameter: float = None,
    radius: float = None,
    pixel_scale: float = None,
    polar: bool = False,
    fft_style: bool = False,
) -> Array:
    """
    Returns a paraxial set of 2d coordinates for each pixel center.

    Parameters
    ----------
    npixels : int
        The output size of the coordinates array to generate.
    diameter : float = None
        The diameter of the coordinates array to generate.
    radius : float = None
        The radius of the coordinates array to generate.
    pixel_scale : float = None
        The pixel scale of the coordinates array to generate.
    polar : bool = False
        Output the coordinates in polar (r, phi) coordinates.
    fft_style : bool = False
        If True, use FFT-style centering. For even npixels this produces integer
        centered coordinates. For odd npixels this is identical to the default.

    Returns
    -------
    coordinates : Array
        The array of pixel center coordinates.
    """
    supplied = sum(value is not None for value in (diameter, radius, pixel_scale))
    if supplied != 1:
        raise ValueError(
            "Exactly one of diameter, radius, or pixel_scale must be provided."
        )

    if diameter is not None:
        pixscale = diameter / npixels
    elif radius is not None:
        pixscale = 2 * radius / npixels
    else:
        pixscale = pixel_scale

    # Default: symmetric pixel-center coordinates (half-integer for even N)
    offsets = (0.0, 0.0)

    # FFT-style: shift by +0.5 pixel for even N so coordinates become integer-centered
    if fft_style and (npixels % 2 == 0):
        offsets = (pixscale / 2.0, pixscale / 2.0)

    # Generate the coordinates
    coords = nd_coords((npixels,) * 2, (pixscale,) * 2, offsets=offsets, indexing="xy")

    # Convert to polar if requested
    if polar:
        return cart2polar(coords)
    return coords
nd_coords

dLux.utils.coordinates.nd_coords(npixels, pixel_scales=1.0, offsets=0.0, indexing='xy') ¤

Returns a set of nd pixel center coordinates, with an optional offset. Each dimension can have a different number of pixels, pixel scale and offset by passing in tuples of values: nd_coords((10, 10), (1, 2), (0, 1)). pixel scale and offset can also be passed in as floats to apply those values to all dimensions, i.e.: nd_coords((10, 10), 1, 0).

The indexing argument is the same as in numpy.meshgrid, i.e.: giving the string ‘ij’ returns a meshgrid with matrix indexing, while ‘xy’ returns a meshgrid with Cartesian indexing. In the 2-D case with inputs of length M and N, the outputs are of shape (N, M) for ‘xy’ indexing and (M, N) for ‘ij’ indexing. In the 3-D case with inputs of length M, N and P, outputs are of shape (N, M, P) for ‘xy’ indexing and (M, N, P) for ‘ij’ indexing.

Parameters:

Name Type Description Default
npixels int | tuple[int, ...]

The number of pixels in each dimension.

required
pixel_scales float | tuple[float, ...] = 1.0

The pixel_scales of each dimension. If a tuple, the length of the tuple must match the number of dimensions. If a float, the same scale is applied to all dimensions.

1.0
offsets float | tuple[float, ...] = 0.0

The offset of the pixel centers in each dimension. If a tuple, the length of the tuple must match the number of dimensions. If a float, the same offset is applied to all dimensions. set to 0.

0.0
indexing str = 'xy'

The indexing of the output. Default is 'xy'. See numpy.meshgrid for more details.

'xy'

Returns:

Name Type Description
coordinates Array

The positions of the pixel centers in the given dimensions.

Source code in dLux/utils/coordinates.py
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
def nd_coords(
    npixels: int | tuple[int, ...],
    pixel_scales: float | tuple[float, ...] = 1.0,
    offsets: float | tuple[float, ...] = 0.0,
    indexing: str = "xy",
) -> Array:
    """
    Returns a set of nd pixel center coordinates, with an optional offset. Each
    dimension can have a different number of pixels, pixel scale and offset by passing
    in tuples of values: `nd_coords((10, 10), (1, 2), (0, 1))`. pixel scale and offset
    can also be passed in as floats to apply those values to all dimensions, i.e.:
    `nd_coords((10, 10), 1, 0)`.

    The indexing argument is the same as in numpy.meshgrid, i.e.: giving the
    string ‘ij’ returns a meshgrid with matrix indexing, while ‘xy’ returns a
    meshgrid with Cartesian indexing. In the 2-D case with inputs of length M
    and N, the outputs are of shape (N, M) for ‘xy’ indexing and (M, N) for
    ‘ij’ indexing. In the 3-D case with inputs of length M, N and P, outputs
    are of shape (N, M, P) for ‘xy’ indexing and (M, N, P) for ‘ij’ indexing.

    Parameters
    ----------
    npixels : int | tuple[int, ...]
        The number of pixels in each dimension.
    pixel_scales : float | tuple[float, ...] = 1.0
        The pixel_scales of each dimension. If a tuple, the length
        of the tuple must match the number of dimensions. If a float, the same
        scale is applied to all dimensions.
    offsets : float | tuple[float, ...] = 0.0
        The offset of the pixel centers in each dimension. If a tuple, the
        length of the tuple must match the number of dimensions. If a float,
        the same offset is applied to all dimensions.
        set to 0.
    indexing : str = 'xy'
        The indexing of the output. Default is 'xy'. See numpy.meshgrid for
        more details.

    Returns
    -------
    coordinates : Array
        The positions of the pixel centers in the given dimensions.
    """
    if indexing not in ["xy", "ij"]:
        raise ValueError("indexing must be either 'xy' or 'ij'.")

    # Validate npixels and ensure tuple
    npixels = _cast_tuple(npixels, "npixels")

    # Get the number of dimensions
    ndim = max(
        len(npixels), _input_len(pixel_scales, "mean"), _input_len(offsets, "std")
    )

    # Validate and ensure tuples
    pixel_scales = _cast_scalar(pixel_scales, ndim, "pixel_scales")
    offsets = _cast_scalar(offsets, ndim, "offsets")

    if len(npixels) != ndim:
        npixels *= ndim

    def pixel_fn(n, offset, scale):
        start = -(n - 1) / 2 * scale - offset
        end = (n - 1) / 2 * scale - offset
        return np.linspace(start, end, n)

    # Generate the linear edges of each axes
    lin_pixels = jtu.map(pixel_fn, npixels, offsets, pixel_scales)

    # Output (x, y) for 2d, else in order.
    positions = np.array(np.meshgrid(*lin_pixels, indexing=indexing))

    # Squeeze the output in case of 1d input
    return np.squeeze(positions)
translate_coords

dLux.utils.coordinates.translate_coords(coords, translation) ¤

Translates the coordinates by to a new centre. Translation must have shape (2,).

Parameters:

Name Type Description Default
coords Array

The input coordinates to translate.

required
translation Array

The translation to apply to the coordinates.

required

Returns:

Name Type Description
coords Array

The translated coordinates.

Source code in dLux/utils/coordinates.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def translate_coords(coords: Array, translation: Array) -> Array:
    """
    Translates the coordinates by to a new centre. Translation must have shape (2,).

    Parameters
    ----------
    coords : Array
        The input coordinates to translate.
    translation : Array
        The translation to apply to the coordinates.

    Returns
    -------
    coords : Array
        The translated coordinates.
    """
    return coords - translation[:, None, None]
compress_coords

dLux.utils.coordinates.compress_coords(coords, compress) ¤

Compresses the coordinates by a given factor. Compress must have shape (2,).

Parameters:

Name Type Description Default
coords Array

The input coordinates to compress.

required
compress Array

The compression to apply to the coordinates.

required

Returns:

Name Type Description
coords Array

The compressed coordinates.

Source code in dLux/utils/coordinates.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def compress_coords(coords: Array, compress: Array) -> Array:
    """
    Compresses the coordinates by a given factor. Compress must have shape (2,).

    Parameters
    ----------
    coords : Array
        The input coordinates to compress.
    compress : Array
        The compression to apply to the coordinates.

    Returns
    -------
    coords : Array
        The compressed coordinates.
    """
    return coords * compress[:, None, None]
shear_coords

dLux.utils.coordinates.shear_coords(coords, shear) ¤

Shears the coordinates by a given factor. Shear must have shape (2,).

Parameters:

Name Type Description Default
coords Array

The input coordinates to shear.

required
shear Array

The shear to apply to the coordinates.

required

Returns:

Name Type Description
coords Array

The sheared coordinates.

Source code in dLux/utils/coordinates.py
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def shear_coords(coords: Array, shear: Array) -> Array:
    """
    Shears the coordinates by a given factor. Shear must have shape (2,).

    Parameters
    ----------
    coords : Array
        The input coordinates to shear.
    shear : Array
        The shear to apply to the coordinates.

    Returns
    -------
    coords : Array
        The sheared coordinates.
    """
    trans_coords = np.transpose(coords, (0, 2, 1))
    return coords + trans_coords * shear[:, None, None]
rotate_coords

dLux.utils.coordinates.rotate_coords(coords, rotation) ¤

Rotates the coordinates by a given angle.

Parameters:

Name Type Description Default
coords Array

The input coordinates to rotate.

required
rotation (float, radians)

The rotation to apply to the coordinates.

required

Returns:

Name Type Description
coords Array

The rotated coordinates.

Source code in dLux/utils/coordinates.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
def rotate_coords(coords: Array, rotation: float) -> Array:
    """
    Rotates the coordinates by a given angle.

    Parameters
    ----------
    coords : Array
        The input coordinates to rotate.
    rotation : float, radians
        The rotation to apply to the coordinates.

    Returns
    -------
    coords : Array
        The rotated coordinates.
    """

    x, y = coords
    new_x = np.cos(-rotation) * x + np.sin(-rotation) * y
    new_y = -np.sin(-rotation) * x + np.cos(-rotation) * y
    return np.array([new_x, new_y])
gen_powers

dLux.utils.coordinates.gen_powers(degree) ¤

Generates the powers required for a 2d polynomial

Parameters:

Name Type Description Default
degree int

Maximum power to generate

required

Returns:

Name Type Description
xpows Array

x axis powers

ypows Array

y axis powers

Source code in dLux/utils/coordinates.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
def gen_powers(degree: int):
    """
    Generates the powers required for a 2d polynomial

    Parameters
    ----------
    degree : int
        Maximum power to generate

    Returns
    -------
    xpows : Array
        x axis powers
    ypows : Array
        y axis powers
    """
    n = triangular_number(degree)
    vals = np.arange(n)

    # Ypows
    tris = triangular_number(np.arange(degree))
    ydiffs = np.repeat(tris, np.arange(1, degree + 1))
    ypows = vals - ydiffs

    # Xpows
    tris = triangular_number(np.arange(1, degree + 1))
    xdiffs = np.repeat(n - np.flip(tris), np.arange(degree, 0, -1))
    xpows = np.flip(vals - xdiffs)

    return np.array([xpows, ypows])
distort_coords

dLux.utils.coordinates.distort_coords(coords, coeffs, pows) ¤

Apply a 2D polynomial distortion to some coordinates

Parameters:

Name Type Description Default
coords Array

Input coordinates to distort

required
coeffs Array

Distortion polynomial coefficients

required
pows Array

Distortion polynomial powers

required

Returns:

Name Type Description
distorted_coords Array

Coords with the distortion applied

Source code in dLux/utils/coordinates.py
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
def distort_coords(coords: Array, coeffs: Array, pows: Array):
    """
    Apply a 2D polynomial distortion to some coordinates

    Parameters
    ----------
    coords : Array
        Input coordinates to distort
    coeffs : Array
        Distortion polynomial coefficients
    pows : Array
        Distortion polynomial powers

    Returns
    -------
    distorted_coords : Array
        Coords with the distortion applied
    """
    pow_base = np.multiply(*(coords[:, None, ...] ** pows[..., None, None]))
    distortion = np.sum(coeffs[..., None, None] * pow_base[None, ...], axis=1)
    return coords + distortion