Skip to content

Commit

Permalink
Add support for compound bounding boxes and ignored bounding box entr…
Browse files Browse the repository at this point in the history
…ies in `grid_from_bounding_box` (#519)
  • Loading branch information
WilliamJamieson authored Oct 24, 2024
1 parent c46e932 commit ccbb066
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

- Synchronize ``region.py`` with the copies of it in JWST and Romancal. [#517]

- Add support for compound bounding boxes and ignored bounding box entries. [#519]

0.21.0 (2024-03-10)
-------------------

Expand Down
58 changes: 57 additions & 1 deletion gwcs/tests/test_wcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import numpy as np
from numpy.testing import assert_allclose, assert_equal

from astropy.modeling import models
from astropy.modeling import models, bind_compound_bounding_box
from astropy.modeling.bounding_box import ModelBoundingBox
from astropy import coordinates as coord
from astropy.io import fits
from astropy import units as u
Expand Down Expand Up @@ -391,6 +392,61 @@ def test_grid_from_bounding_box_step():
with pytest.raises(ValueError):
grid_from_bounding_box(bb, step=(1, 2, 1))

def test_grid_from_model_bounding_box():
bbox = ((-1, 1), (0, 1))
# Truth grid
grid_truth = grid_from_bounding_box(bbox)

# Create a bounding box
model = models.Const2D() & models.Const1D()
model.inputs = ("x", "y", "slit_name")
model.bounding_box = ModelBoundingBox(
{
"x": bbox[0],
"y": bbox[1],
},
model=model,
ignored=["slit_name"],
order="F",
)
grid = grid_from_bounding_box(model.bounding_box)

assert np.all(grid == grid_truth)


def test_grid_from_compound_bounding_box():
bbox = ((-1, 1), (0, 1))
# Truth grid
grid_truth = grid_from_bounding_box(bbox)

# Create a compound bounding box
model = models.Const2D() & models.Const1D()
model.inputs = ("x", "y", "slit_name")
bind_compound_bounding_box(
model,
{
(200,) : {
"x": bbox[0],
"y": bbox[1],
},
(300,) :{
"x": (-2, 2),
"y": (0, 2),
}
},
[("slit_name",)],
order="F",
)
grid = grid_from_bounding_box(model.bounding_box, selector=(200,))

assert np.all(grid == grid_truth)

# Capture errors
with pytest.raises(ValueError, match=r"Cannot use selector with a non-CompoundBoundingBox"):
grid_from_bounding_box(model.bounding_box[(300,)], selector=(300,))
with pytest.raises(ValueError, match=r"selector must be set when bounding_box is a CompoundBoundingBox"):
grid_from_bounding_box(model.bounding_box)


def test_wcs_from_points():
np.random.seed(0)
Expand Down
28 changes: 26 additions & 2 deletions gwcs/wcstools.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from astropy.modeling.core import Model
from astropy.modeling import projections
from astropy.modeling import models, fitting
from astropy.modeling.bounding_box import CompoundBoundingBox, ModelBoundingBox
from astropy import coordinates as coord
from astropy import units as u

Expand Down Expand Up @@ -139,7 +140,7 @@ def _frame2D_transform(fiducial, **kwargs):
}


def grid_from_bounding_box(bounding_box, step=1, center=True):
def grid_from_bounding_box(bounding_box, step=1, center=True, selector=None):
"""
Create a grid of input points from the WCS bounding_box.
Expand All @@ -151,11 +152,14 @@ def grid_from_bounding_box(bounding_box, step=1, center=True):
Parameters
----------
bounding_box : tuple
bounding_box : tuple | ~astropy.modeling.bounding_box.ModelBoundingBox | ~astropy.modeling.bounding_box.CompoundBoundingBox
The bounding_box of a WCS object, `~gwcs.wcs.WCS.bounding_box`.
step : scalar or tuple
Step size for grid in each dimension. Scalar applies to all dimensions.
center : bool
selector : tuple | None
If selector is set then it must be a selector tuple and bounding_box must
be a CompoundBoundingBox.
The bounding_box is in order of X, Y [, Z] and the output will be in the
same order.
Expand Down Expand Up @@ -187,6 +191,26 @@ def grid_from_bounding_box(bounding_box, step=1, center=True):
"""
def _bbox_to_pixel(bbox):
return (np.floor(bbox[0] + 0.5), np.ceil(bbox[1] - 0.5))

if selector is not None and not isinstance(bounding_box, CompoundBoundingBox):
raise ValueError("Cannot use selector with a non-CompoundBoundingBox")

if isinstance(bounding_box, CompoundBoundingBox):
if selector is None:
raise ValueError("selector must be set when bounding_box is a CompoundBoundingBox")

bounding_box = bounding_box[selector]

if isinstance(bounding_box, ModelBoundingBox):
input_names = bounding_box.model.inputs

# Get tuple of tuples of the bounding box values
bounding_box = tuple(
tuple(bounding_box[name])
for name in input_names
if name not in bounding_box.ignored_inputs
)

# 1D case
if np.isscalar(bounding_box[0]):
nd = 1
Expand Down

0 comments on commit ccbb066

Please sign in to comment.