47 #include "lsst/afw/table/io/Persistable.cc" 58 int const SERIALIZATION_VERSION = 1;
66 double const TIGHT_FITS_TOL = 0.0001;
68 class SkyWcsPersistenceHelper {
71 table::Key<table::Array<std::uint8_t>>
wcs;
73 static SkyWcsPersistenceHelper
const&
get() {
74 static SkyWcsPersistenceHelper instance;
79 SkyWcsPersistenceHelper(
const SkyWcsPersistenceHelper&) =
delete;
80 SkyWcsPersistenceHelper& operator=(
const SkyWcsPersistenceHelper&) =
delete;
83 SkyWcsPersistenceHelper(SkyWcsPersistenceHelper&&) =
delete;
84 SkyWcsPersistenceHelper& operator=(SkyWcsPersistenceHelper&&) =
delete;
87 SkyWcsPersistenceHelper()
89 wcs(schema.addField<table::Array<std::uint8_t>>(
"wcs",
"wcs string representation",
"")) {
90 schema.getCitizen().markPersistent();
94 class SkyWcsFactory :
public table::io::PersistableFactory {
96 explicit SkyWcsFactory(
std::string const&
name) : table::io::PersistableFactory(name) {}
99 CatalogVector
const& catalogs)
const override {
100 SkyWcsPersistenceHelper
const&
keys = SkyWcsPersistenceHelper::get();
104 table::BaseRecord
const& record = catalogs.front().front();
106 return SkyWcs::readString(stringRep);
110 std::string getSkyWcsPersistenceName() {
return "SkyWcs"; }
112 SkyWcsFactory registration(getSkyWcsPersistenceName());
120 auto const initialFrameDict = initialWcs->getFrameDict();
121 auto const iwcToSkyMap = initialFrameDict->getMapping(
"IWC",
"SKY");
122 auto const pixelFrame = initialFrameDict->getFrame(
"PIXELS");
123 auto const iwcFrame = initialFrameDict->getFrame(
"IWC");
124 auto const skyFrame = initialFrameDict->getFrame(
"SKY");
127 ndarray::Array<double, 2, 2> fieldAngleToIwcNdArray = ndarray::allocate(2, 2);
128 asEigenMatrix(fieldAngleToIwcNdArray) = orientationAndFlipXMatrix * 180.0 /
lsst::geom::PI;
129 auto const pixelsToFieldAngleMap = pixelsToFieldAngle.getMapping();
130 auto const fieldAngleToIwcMap =
ast::MatrixMap(fieldAngleToIwcNdArray);
131 auto const pixelsToIwcMap = pixelsToFieldAngleMap->then(fieldAngleToIwcMap);
132 auto finalFrameDict =
ast::FrameDict(*pixelFrame, pixelsToIwcMap, *iwcFrame);
133 finalFrameDict.addFrame(
"IWC", *iwcToSkyMap, *
skyFrame);
134 return finalFrameDict;
141 Eigen::Matrix2d cdMatrix;
142 double orientRad = orientation.
asRadians();
144 double xmult = flipX ? 1.0 : -1.0;
145 cdMatrix(0, 0) =
std::cos(orientRad) * scaleDeg * xmult;
146 cdMatrix(0, 1) =
std::sin(orientRad) * scaleDeg;
147 cdMatrix(1, 0) = -
std::sin(orientRad) * scaleDeg * xmult;
148 cdMatrix(1, 1) =
std::cos(orientRad) * scaleDeg;
167 double const side = 1.0;
175 auto skyLL = skyVec[0].getVector();
176 auto skyDx = skyVec[1].getVector() - skyLL;
177 auto skyDy = skyVec[2].getVector() - skyLL;
182 double skyAreaSq = skyDx.cross(skyDy).getSquaredNorm();
193 auto const crvalRad =
skyFrame->getSkyRef();
200 return pixelToIwcTransform.getJacobian(pixel);
209 return std::make_shared<SkyWcs>(*metadata);
222 auto const iwcToSky = thisDict->getMapping(
"IWC",
"SKY");
223 auto const gridToSky = gridToPixel.
then(*pixelToIwc).
then(*iwcToSky);
228 os <<
"Encoding=FITS-WCS, CDMatrix=1, FitsAxisOrder=<copy>, FitsTol=" << TIGHT_FITS_TOL;
232 if (nObjectsWritten == 0) {
235 "Could not represent this SkyWcs using FITS-WCS metadata");
240 return tanWcs->getFitsMetadata(
true);
261 return _linearizePixelToSky(
skyToPixel(coord), coord, skyUnit);
265 return _linearizePixelToSky(pix,
pixelToSky(pix), skyUnit);
270 return _linearizeSkyToPixel(
skyToPixel(coord), coord, skyUnit);
275 return _linearizeSkyToPixel(pix,
pixelToSky(pix), skyUnit);
295 is >> shortClassName;
308 os <<
"The AST serialization was read as a " << astObjectPtr->getClassName()
309 <<
" instead of a FrameSet";
313 return std::make_shared<SkyWcs>(frameDict);
333 return std::make_unique<SkyWcs>(*this);
347 SkyWcsPersistenceHelper
const&
keys = SkyWcsPersistenceHelper::get();
355 : _frameDict(frameDict), _transform(), _pixelOrigin(), _pixelScaleAtOrigin(0 *
lsst::geom::radians) {
362 for (
auto const& domainName : domainNames) {
365 if (
frame->getNAxes() != 2) {
368 " axes instead of 2");
370 auto desiredClassName = domainName ==
"SKY" ?
"SkyFrame" :
"Frame";
371 if (
frame->getClassName() != desiredClassName) {
373 "Frame " + domainName +
" is of type " +
frame->getClassName() +
374 " instead of " + desiredClassName);
376 }
else if (domainName !=
"ACTUAL_PIXELS") {
379 "No frame with domain " + domainName +
" found");
385 if (baseDomain !=
"ACTUAL_PIXELS" && baseDomain !=
"PIXELS") {
387 "Base frame has domain " + baseDomain +
" instead of PIXELS or ACTUAL_PIXELS");
392 if (currentDomain !=
"SKY") {
394 "Current frame has domain " + currentDomain +
" instead of SKY");
397 return frameDict.
copy();
406 const double side = 1.0;
412 m(0, 0) = dsky10.first.asAngularUnits(skyUnit) / side;
413 m(0, 1) = dsky01.first.asAngularUnits(skyUnit) / side;
414 m(1, 0) = dsky10.second.asAngularUnits(skyUnit) / side;
415 m(1, 1) = dsky01.second.asAngularUnits(skyUnit) / side;
417 Eigen::Vector2d sky00v;
418 sky00v << sky00.getX(), sky00.getY();
419 Eigen::Vector2d pix00v;
420 pix00v << pix00.getX(), pix00.getY();
434 double const dx = 1000;
452 bool modifyActualPixels) {
453 auto const pixelMapping = pixelTransform.
getMapping();
455 bool const hasActualPixels = oldFrameDict->hasDomain(
"ACTUAL_PIXELS");
456 auto const pixelFrame = oldFrameDict->getFrame(
"PIXELS",
false);
457 auto const iwcFrame = oldFrameDict->getFrame(
"IWC",
false);
458 auto const skyFrame = oldFrameDict->getFrame(
"SKY",
false);
459 auto const oldPixelToIwc = oldFrameDict->getMapping(
"PIXELS",
"IWC");
460 auto const iwcToSky = oldFrameDict->getMapping(
"IWC",
"SKY");
464 if (hasActualPixels) {
465 auto const actualPixelFrame = oldFrameDict->getFrame(
"ACTUAL_PIXELS",
false);
466 auto const oldActualPixelToPixels = oldFrameDict->getMapping(
"ACTUAL_PIXELS",
"PIXELS");
468 if (modifyActualPixels) {
469 newActualPixelsToPixels = pixelMapping->then(*oldActualPixelToPixels).simplified();
470 newPixelToIwc = oldPixelToIwc;
472 newActualPixelsToPixels = oldActualPixelToPixels;
473 newPixelToIwc = pixelMapping->then(*oldPixelToIwc).simplified();
476 std::make_shared<ast::FrameDict>(*actualPixelFrame, *newActualPixelsToPixels, *pixelFrame);
477 newFrameDict->addFrame(
"PIXELS", *newPixelToIwc, *iwcFrame);
479 newPixelToIwc = pixelMapping->then(*oldPixelToIwc).simplified();
480 newFrameDict = std::make_shared<ast::FrameDict>(*pixelFrame, *newPixelToIwc, *iwcFrame);
482 newFrameDict->addFrame(
"IWC", *iwcToSky, *
skyFrame);
483 return std::make_shared<SkyWcs>(*newFrameDict);
487 return std::make_shared<SkyWcs>(metadata,
strip);
491 Eigen::Matrix2d
const& cdMatrix,
std::string const& projection) {
493 return std::make_shared<SkyWcs>(*metadata);
499 auto frameDict = makeSkyWcsFrameDict(pixelsToFieldAngle, orientation, flipX, boresight, projection);
500 return std::make_shared<SkyWcs>(frameDict);
504 Eigen::Matrix2d
const& cdMatrix, Eigen::MatrixXd
const& sipA,
505 Eigen::MatrixXd
const& sipB) {
507 return std::make_shared<SkyWcs>(*metadata);
511 Eigen::Matrix2d
const& cdMatrix, Eigen::MatrixXd
const& sipA,
512 Eigen::MatrixXd
const& sipB, Eigen::MatrixXd
const& sipAp,
513 Eigen::MatrixXd
const& sipBp) {
515 return std::make_shared<SkyWcs>(*metadata);
520 auto iwcToSky = wcs.
getFrameDict()->getMapping(
"IWC",
"SKY");
521 return std::make_shared<TransformPoint2ToSpherePoint>(*iwcToSky, simplify);
526 return std::make_shared<TransformPoint2ToPoint2>(*pixelToIwc, simplify);
std::pair< Angle, Angle > getTangentPlaneOffset(SpherePoint const &other) const
Get the offset from a tangent plane centered at this point to another point.
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
std::shared_ptr< SkyWcs > getTanWcs(lsst::geom::Point2D const &pixel) const
Get a local TAN WCS approximation to this WCS at the specified pixel position.
constexpr double asRadians() const noexcept
Return an Angle's value in radians.
MatrixMap is a form of Mapping which performs a general linear transformation.
constexpr double asDegrees() const noexcept
Return an Angle's value in degrees.
lsst::geom::Point2D skyToPixel(lsst::geom::SpherePoint const &sky) const
Compute pixel position(s) from sky position(s)
An object passed to Persistable::write to allow it to persist itself.
lsst::geom::SpherePoint pixelToSky(lsst::geom::Point2D const &pixel) const
Compute sky position(s) from pixel position(s)
bool isFits() const
Return true getFitsMetadata(true) will succeed, false if not.
table::PointKey< double > crpix
Interface supporting iteration over heterogenous containers.
Point2D getPosition(AngleUnit unit) const noexcept
Return longitude, latitude as a Point2D object.
def scale(algorithm, min, max=None, frame=None)
Channel provides input/output of AST objects.
SeriesMap then(Mapping const &next) const
Return a series compound mapping this(first(input)) containing shallow copies of the original...
std::shared_ptr< SkyWcs > makeModifiedWcs(TransformPoint2ToPoint2 const &pixelTransform, SkyWcs const &wcs, bool modifyActualPixels)
Create a new SkyWcs whose pixels are transformed by pixelTransform, as described below.
std::string getPythonModule() const override
Return the fully-qualified Python module that should be imported to guarantee that its factory is reg...
table::PointKey< double > crval
std::shared_ptr< ast::FrameDict > readLsstSkyWcs(daf::base::PropertySet &metadata, bool strip=true)
Read an LSST celestial WCS FrameDict from a FITS header.
lsst::geom::SpherePoint getSkyOrigin() const
Get the sky origin, the celestial fiducial point.
static int constexpr CURRENT
index of current frame
bool equals(typehandling::Storable const &other) const noexcept override
Compare this object to another Storable.
std::shared_ptr< const ast::FrameDict > getFrameDict() const
Get the contained FrameDict.
AngleUnit constexpr radians
constant with units of radians
A class representing an angle.
A specialized form of Channel which reads and writes FITS header cards.
table::Key< table::Array< std::uint8_t > > wcs
Transform< Point2Endpoint, Point2Endpoint > TransformPoint2ToPoint2
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
A WinMap is a linear Mapping which transforms a rectangular window in one coordinate system into a si...
Eigen::Matrix2d getCdMatrix() const
Get the 2x2 CD matrix at the pixel origin.
std::shared_ptr< const TransformPoint2ToSpherePoint > getTransform() const
Get a TransformPoint2ToSpherePoint that transforms pixels to sky in the forward direction and sky to ...
AngleUnit constexpr degrees
constant with units of degrees
SkyFrame is a specialised form of Frame which describes celestial longitude/latitude coordinate syste...
A base class for image defects.
bool hasFitsApproximation() const
Does this SkyWcs have an approximate SkyWcs that can be represented as standard FITS WCS...
std::shared_ptr< SkyWcs > makeFlippedWcs(SkyWcs const &wcs, bool flipLR, bool flipTB, lsst::geom::Point2D const ¢er)
Return a copy of a FITS-WCS with pixel positions flipped around a specified center.
Frame is used to represent a coordinate system.
std::string toString() const override
Create a string representation of this object.
std::shared_ptr< Frame > getFrame(std::string const &domain, bool copy=true) const
Variant of getFrame(int, bool) where the frame is specified by domain name.
std::shared_ptr< FrameDict > copy() const
Return a deep copy of this object.
static std::shared_ptr< SkyWcs > readStream(std::istream &is)
Deserialize a SkyWcs from an input stream.
lsst::geom::AffineTransform linearizePixelToSky(lsst::geom::SpherePoint const &coord, lsst::geom::AngleUnit const &skyUnit) const
Return the local linear approximation to pixelToSky at a point given in sky coordinates.
std::shared_ptr< daf::base::PropertyList > getPropertyListFromFitsChan(ast::FitsChan &fitsChan)
Copy values from an AST FitsChan into a PropertyList.
T dynamic_pointer_cast(T... args)
static std::string getShortClassName()
std::shared_ptr< TransformPoint2ToPoint2 > getPixelToIntermediateWorldCoords(SkyWcs const &wcs, bool simplify=true)
Return a transform from pixel coordinates to intermediate world coordinates.
std::shared_ptr< SkyWcs > makeTanSipWcs(lsst::geom::Point2D const &crpix, lsst::geom::SpherePoint const &crval, Eigen::Matrix2d const &cdMatrix, Eigen::MatrixXd const &sipA, Eigen::MatrixXd const &sipB)
Construct a TAN-SIP SkyWcs with forward SIP distortion terms and an iterative inverse.
std::shared_ptr< TransformPoint2ToSpherePoint > getIntermediateWorldCoordsToSky(SkyWcs const &wcs, bool simplify=true)
Return a transform from intermediate world coordinates to sky.
Reports errors in the logical structure of the program.
ShiftMap is a linear Mapping which shifts each axis by a specified constant value.
std::shared_ptr< typehandling::Storable > cloneStorable() const override
Create a new SkyWcs that is a copy of this one.
std::shared_ptr< RecordT > src
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
std::ostream & operator<<(std::ostream &os, Storable const &storable)
Output operator for Storable.
std::shared_ptr< daf::base::PropertyList > makeTanSipMetadata(lsst::geom::Point2D const &crpix, lsst::geom::SpherePoint const &crval, Eigen::Matrix2d const &cdMatrix, Eigen::MatrixXd const &sipA, Eigen::MatrixXd const &sipB)
Make metadata for a TAN-SIP WCS without inverse matrices.
std::shared_ptr< SkyWcs > copyAtShiftedPixelOrigin(lsst::geom::Extent2D const &shift) const
Return a copy of this SkyWcs with the pixel origin shifted by the specified amount.
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
std::shared_ptr< daf::base::PropertyList > makeSimpleWcsMetadata(lsst::geom::Point2D const &crpix, lsst::geom::SpherePoint const &crval, Eigen::Matrix2d const &cdMatrix, std::string const &projection="TAN")
Make FITS metadata for a simple FITS WCS (one with no distortion).
Point in an unspecified spherical coordinate system.
static std::shared_ptr< SkyWcs > readString(std::string &str)
Deserialize a SkyWcs from a string, using the same format as readStream.
lsst::geom::Point2D getPixelOrigin() const
Get the pixel origin, in pixels, using the LSST convention.
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
SkyWcs(SkyWcs const &)=default
Class for storing generic metadata.
std::string writeString() const
Serialize this SkyWcs to a string, using the same format as writeStream.
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
std::shared_ptr< daf::base::PropertyList > getFitsMetadata(bool precise=false) const
Return the WCS as FITS WCS metadata.
Eigen::Matrix2d makeCdMatrix(lsst::geom::Angle const &scale, lsst::geom::Angle const &orientation=0 *lsst::geom::degrees, bool flipX=false)
Make a WCS CD matrix.
String-based source and sink for channels.
lsst::geom::SpherePoint SpherePoint
table::PointKey< int > pixel
void writeStream(std::ostream &os) const
Serialize this SkyWcs to an output stream.
ItemVariant const * other
static int constexpr BASE
index of base frame
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
table::Key< int > version
bool isFlipped() const
Does the WCS follow the convention of North=Up, East=Left?
Extent< double, 2 > Extent2D
lsst::geom::AffineTransform linearizeSkyToPixel(lsst::geom::SpherePoint const &coord, lsst::geom::AngleUnit const &skyUnit) const
Return the local linear approximation to skyToPixel at a point given in sky coordinates.
Reports errors from accepting an object of an unexpected or inappropriate type.
lsst::geom::Angle getPixelScale() const
Get the pixel scale at the pixel origin.
A FrameSet whose frames can be referenced by domain name.
bool operator==(SkyWcs const &other) const
Equality is based on the string representations being equal.
std::shared_ptr< Object > read()
Read an object from a channel.
A stream for ast::Channel.
A FrameSet consists of a set of one or more Frames (which describe coordinate systems), connected together by Mappings (which describe how the coordinate systems are inter-related).
double constexpr PI
The ratio of a circle's circumference to diameter.
A class used to convert scalar POD types such as double to Angle.
bool hasDomain(std::string const &domain) const
Return True if a frame in this FrameDict has the specified domain.
Reports errors that are due to events beyond the control of the program.
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
static bool singleClassEquals(T const &lhs, Storable const &rhs)
Test if a Storable is of a particular class and equal to another object.