Our code currently allows the image, mask, and variance planes of a MaskedImage to have different XY0 origins, and hence different bounding boxes:
The same problem also affects all of the spatially-aware non-Image objects attached to Exposure (e.g. Wcs and Psf: if the user calls setXY0 on the Exposure object, none of these objects are modified or notified, and hence they remain in the old coordinate system.
Implementing DM-7565 will add new problems of the same type.
The simplest solution by far is to remove setXY0 (at least as a public method). This does not affect the primary use of XY0 (making the coordinate system of a subimage the same as its parent), which happens at construction and is hence safe since all-subobjects can be set consistently.
Instead, I propose adding a shiftedTo method to Image, Mask, and MaskedImage, which will return a view of the image with xy0 modified. For convenience and clarity I also propose adding shiftedBy, which takes an Extent2I and applies a relative offset.
I do not propose adding these methods to Exposure, because implementing them correctly there would require both implementing a shiftedTo method on all of Exposure's components. I think it's likely that any code that currently calls Exposure.setXY0 can and should be rewritten to avoid doing so.
The shiftedTo and shiftedBy names follow this recommendation in the C++ style guide, which I'd like to see us start using more often (especially in afw.geom) to avoid confusion between in-place and return-new operations.
Whether setXY0 is kept as a private method is left as an implementation detail (but if it is, it should of course be renamed to to _setXY0).