diff --git a/include/lsst/afw/cameraGeom/TransformMap.h b/include/lsst/afw/cameraGeom/TransformMap.h index d0eba5c35..537959f8b 100644 --- a/include/lsst/afw/cameraGeom/TransformMap.h +++ b/include/lsst/afw/cameraGeom/TransformMap.h @@ -39,6 +39,8 @@ namespace lsst { namespace afw { namespace cameraGeom { +class DetectorBase; + /** * A registry of 2-dimensional coordinate transforms for a specific camera. * @@ -212,6 +214,23 @@ class TransformMap final : public table::io::PersistableFacade, pu */ bool isPersistable() const noexcept override { return true; } + /** + * Return an AST FrameSet with the standard transforms for this camera. + * + * @param[in] detectors Detectors to include. + * @param[in] focalPlaneUnit Units of the FOCAL_PLANE system. + * + * The 'ident' names of the frames are: + * + * - FOCAL_PLANE + * - FIELD_ANGLE + * - DETECTOR_{id:03} (ACTUAL_PIXELS if available, PIXELS otherwise). + */ + std::unique_ptr makeFrameSet( + std::vector> const & detectors, + std::string const & focalPlaneUnit = "mm" + ) const; + private: // Helper class used in persistence. class Factory; diff --git a/python/lsst/afw/cameraGeom/_transformMap.cc b/python/lsst/afw/cameraGeom/_transformMap.cc index 7935a9970..475a4a8b8 100644 --- a/python/lsst/afw/cameraGeom/_transformMap.cc +++ b/python/lsst/afw/cameraGeom/_transformMap.cc @@ -31,6 +31,7 @@ #include "lsst/afw/table/io/python.h" #include "lsst/afw/cameraGeom/CameraSys.h" #include "lsst/afw/cameraGeom/TransformMap.h" +#include "lsst/afw/cameraGeom/Detector.h" namespace py = pybind11; using namespace py::literals; @@ -77,6 +78,7 @@ void declareTransformMap(lsst::cpputils::python::WrapperCollection &wrappers) { cls.def("getTransform", &TransformMap::getTransform, "fromSys"_a, "toSys"_a); cls.def("getConnections", &TransformMap::getConnections); cls.def("getFocalPlaneParity", &TransformMap::getFocalPlaneParity); + cls.def("makeFrameSet", &TransformMap::makeFrameSet, "detectors"_a, "focalPlaneUnit"_a = "mm"); table::io::python::addPersistableMethods(cls); }); wrappers.wrapType(PyTransformMapConnection(transformMap, "Connection"), [](auto &mod, auto &cls) { diff --git a/src/cameraGeom/TransformMap.cc b/src/cameraGeom/TransformMap.cc index 2181ca7e5..d1757b7cc 100644 --- a/src/cameraGeom/TransformMap.cc +++ b/src/cameraGeom/TransformMap.cc @@ -32,6 +32,7 @@ #include "lsst/afw/table/io/CatalogVector.h" #include "lsst/afw/table/io/Persistable.cc" #include "lsst/afw/cameraGeom/TransformMap.h" +#include "lsst/afw/cameraGeom/Detector.h" namespace lsst { namespace afw { @@ -279,6 +280,71 @@ TransformMap::TransformMap(std::vector &&connections) std::vector TransformMap::getConnections() const { return _connections; } +std::unique_ptr TransformMap::makeFrameSet( + std::vector> const & detectors, + std::string const & focalPlaneUnit +) const { + // We use copy=false to extract each frame from the internal FrameSet, + // since it will always be copied when adding it to the new one. We then + // set the 'ident' value on a shallow reference to the new frame. + auto result = std::make_unique(*_frameSet->getFrame(ast::FrameSet::BASE, false)); + { + auto fp_frame = result->getFrame(ast::FrameSet::BASE, false); + fp_frame->setIdent("FOCAL_PLANE"); + fp_frame->setTitle("Focal Plane Coordinates"); + fp_frame->setUnit(1, focalPlaneUnit); + fp_frame->setUnit(2, focalPlaneUnit); + fp_frame->setLabel(1, "x"); + fp_frame->setLabel(2, "y"); + } + { + int old_frame_id = _getFrame(FIELD_ANGLE); + result->addFrame( + ast::FrameSet::BASE, + *_frameSet->getMapping(ast::FrameSet::BASE, old_frame_id), + *_frameSet->getFrame(old_frame_id, false) + ); + auto frame = result->getFrame(ast::FrameSet::CURRENT, false); + frame->setIdent("FIELD_ANGLE"); + frame->setTitle("Field Angle Coordinates"); + frame->setUnit(1, "rad"); + frame->setUnit(2, "rad"); + frame->setLabel(1, "x"); + frame->setLabel(2, "y"); + } + for (auto const & detector : detectors) { + CameraSys sys(ACTUAL_PIXELS, detector->getName()); + auto id_iter = _frameIds.find(sys); + if (id_iter == _frameIds.end()) { + sys = CameraSys(PIXELS, detector->getName()); + id_iter = _frameIds.find(sys); + if (id_iter == _frameIds.end()) { + std::ostringstream buffer; + buffer << "Unsupported coordinate system: " << sys; + throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, buffer.str()); + } + } + result->addFrame( + ast::FrameSet::BASE, + *_frameSet->getMapping(ast::FrameSet::BASE, id_iter->second), + *_frameSet->getFrame(id_iter->second, false) + ); + auto frame = result->getFrame(ast::FrameSet::CURRENT, false); + frame->setIdent((boost::format("DETECTOR_%03d") % detector->getId()).str()); + frame->setTitle((boost::format("Pixel Coordinates (Detector %d)") % detector->getId()).str()); + frame->setUnit(1, "pix"); + frame->setUnit(2, "pix"); + frame->setLabel(1, "x"); + frame->setLabel(2, "y"); + auto bbox = detector->getBBox(); + frame->setBottom(1, bbox.getMinX()); + frame->setTop(1, bbox.getMaxX()); + frame->setBottom(2, bbox.getMinY()); + frame->setTop(2, bbox.getMaxY()); + } + return result; +} + namespace { struct PersistenceHelper {