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",
"")) {}
92 class SkyWcsFactory :
public table::io::PersistableFactory {
94 explicit SkyWcsFactory(
std::string const&
name) : table::io::PersistableFactory(name) {}
97 CatalogVector
const& catalogs)
const override {
98 SkyWcsPersistenceHelper
const&
keys = SkyWcsPersistenceHelper::get();
102 table::BaseRecord
const& record = catalogs.front().front();
104 return SkyWcs::readString(stringRep);
108 std::string getSkyWcsPersistenceName() {
return "SkyWcs"; }
110 SkyWcsFactory registration(getSkyWcsPersistenceName());
117 auto const initialWcs =
119 auto const initialFrameDict = initialWcs->getFrameDict();
120 auto const iwcToSkyMap = initialFrameDict->getMapping(
"IWC",
"SKY");
121 auto const pixelFrame = initialFrameDict->getFrame(
"PIXELS");
122 auto const iwcFrame = initialFrameDict->getFrame(
"IWC");
123 auto const skyFrame = initialFrameDict->getFrame(
"SKY");
126 ndarray::Array<double, 2, 2> fieldAngleToIwcNdArray = ndarray::allocate(2, 2);
127 asEigenMatrix(fieldAngleToIwcNdArray) = orientationAndFlipXMatrix * 180.0 /
lsst::geom::PI;
128 auto const pixelsToFieldAngleMap = pixelsToFieldAngle.getMapping();
129 auto const fieldAngleToIwcMap =
ast::MatrixMap(fieldAngleToIwcNdArray);
130 auto const pixelsToIwcMap = pixelsToFieldAngleMap->then(fieldAngleToIwcMap);
131 auto finalFrameDict =
ast::FrameDict(*pixelFrame, pixelsToIwcMap, *iwcFrame);
132 finalFrameDict.addFrame(
"IWC", *iwcToSkyMap, *
skyFrame);
133 return finalFrameDict;
140 Eigen::Matrix2d cdMatrix;
141 double orientRad = orientation.
asRadians();
143 double xmult = flipX ? 1.0 : -1.0;
144 cdMatrix(0, 0) =
std::cos(orientRad) * scaleDeg * xmult;
145 cdMatrix(0, 1) =
std::sin(orientRad) * scaleDeg;
146 cdMatrix(1, 0) = -
std::sin(orientRad) * scaleDeg * xmult;
147 cdMatrix(1, 1) =
std::cos(orientRad) * scaleDeg;
166 double const side = 1.0;
176 auto skyLL = skyVec[0].getVector();
177 auto skyDx = skyVec[1].getVector() - skyLL;
178 auto skyDy = skyVec[2].getVector() - skyLL;
183 double skyAreaSq = skyDx.cross(skyDy).getSquaredNorm();
194 auto const crvalRad =
skyFrame->getSkyRef();
201 return pixelToIwcTransform.getJacobian(pixel);
210 return std::make_shared<SkyWcs>(*metadata);
223 auto const iwcToSky = thisDict->getMapping(
"IWC",
"SKY");
224 auto const gridToSky = gridToPixel.
then(*pixelToIwc).
then(*iwcToSky);
229 os <<
"Encoding=FITS-WCS, CDMatrix=1, FitsAxisOrder=<copy>, FitsTol=" << TIGHT_FITS_TOL;
233 if (nObjectsWritten == 0) {
236 "Could not represent this SkyWcs using FITS-WCS metadata");
241 return tanWcs->getFitsMetadata(
true);
262 return _linearizePixelToSky(
skyToPixel(coord), coord, skyUnit);
266 return _linearizePixelToSky(pix,
pixelToSky(pix), skyUnit);
271 return _linearizeSkyToPixel(
skyToPixel(coord), coord, skyUnit);
276 return _linearizeSkyToPixel(pix,
pixelToSky(pix), skyUnit);
296 is >> shortClassName;
309 os <<
"The AST serialization was read as a " << astObjectPtr->getClassName()
310 <<
" instead of a FrameSet";
314 return std::make_shared<SkyWcs>(frameDict);
334 return std::make_unique<SkyWcs>(*this);
340 os <<
"FITS standard SkyWcs:";
342 os <<
"Non-standard SkyWcs (Frames: ";
345 for (
size_t i = 1; i <=
getFrameDict()->getAllDomains().size(); ++i) {
346 os << delimiter <<
getFrameDict()->getFrame(i)->getDomain();
367 SkyWcsPersistenceHelper
const&
keys = SkyWcsPersistenceHelper::get();
375 : _frameDict(frameDict), _transform(), _pixelOrigin(), _pixelScaleAtOrigin(0 *
lsst::geom::radians) {
382 for (
auto const& domainName : domainNames) {
385 if (
frame->getNAxes() != 2) {
388 " axes instead of 2");
390 auto desiredClassName = domainName ==
"SKY" ?
"SkyFrame" :
"Frame";
391 if (
frame->getClassName() != desiredClassName) {
393 "Frame " + domainName +
" is of type " +
frame->getClassName() +
394 " instead of " + desiredClassName);
396 }
else if (domainName !=
"ACTUAL_PIXELS") {
399 "No frame with domain " + domainName +
" found");
405 if (baseDomain !=
"ACTUAL_PIXELS" && baseDomain !=
"PIXELS") {
407 "Base frame has domain " + baseDomain +
" instead of PIXELS or ACTUAL_PIXELS");
412 if (currentDomain !=
"SKY") {
414 "Current frame has domain " + currentDomain +
" instead of SKY");
417 return frameDict.
copy();
426 const double side = 1.0;
432 m(0, 0) = dsky10.first.asAngularUnits(skyUnit) / side;
433 m(0, 1) = dsky01.first.asAngularUnits(skyUnit) / side;
434 m(1, 0) = dsky10.second.asAngularUnits(skyUnit) / side;
435 m(1, 1) = dsky01.second.asAngularUnits(skyUnit) / side;
437 Eigen::Vector2d sky00v;
438 sky00v << sky00.getX(), sky00.getY();
439 Eigen::Vector2d pix00v;
440 pix00v << pix00.getX(), pix00.getY();
454 double const dx = 1000;
472 bool modifyActualPixels) {
473 auto const pixelMapping = pixelTransform.
getMapping();
475 bool const hasActualPixels = oldFrameDict->hasDomain(
"ACTUAL_PIXELS");
476 auto const pixelFrame = oldFrameDict->getFrame(
"PIXELS",
false);
477 auto const iwcFrame = oldFrameDict->getFrame(
"IWC",
false);
478 auto const skyFrame = oldFrameDict->getFrame(
"SKY",
false);
479 auto const oldPixelToIwc = oldFrameDict->getMapping(
"PIXELS",
"IWC");
480 auto const iwcToSky = oldFrameDict->getMapping(
"IWC",
"SKY");
484 if (hasActualPixels) {
485 auto const actualPixelFrame = oldFrameDict->getFrame(
"ACTUAL_PIXELS",
false);
486 auto const oldActualPixelToPixels = oldFrameDict->getMapping(
"ACTUAL_PIXELS",
"PIXELS");
488 if (modifyActualPixels) {
489 newActualPixelsToPixels = pixelMapping->then(*oldActualPixelToPixels).simplified();
490 newPixelToIwc = oldPixelToIwc;
492 newActualPixelsToPixels = oldActualPixelToPixels;
493 newPixelToIwc = pixelMapping->then(*oldPixelToIwc).simplified();
496 std::make_shared<ast::FrameDict>(*actualPixelFrame, *newActualPixelsToPixels, *pixelFrame);
497 newFrameDict->addFrame(
"PIXELS", *newPixelToIwc, *iwcFrame);
499 newPixelToIwc = pixelMapping->then(*oldPixelToIwc).simplified();
500 newFrameDict = std::make_shared<ast::FrameDict>(*pixelFrame, *newPixelToIwc, *iwcFrame);
502 newFrameDict->addFrame(
"IWC", *iwcToSky, *
skyFrame);
503 return std::make_shared<SkyWcs>(*newFrameDict);
507 return std::make_shared<SkyWcs>(metadata,
strip);
511 Eigen::Matrix2d
const& cdMatrix,
std::string const& projection) {
513 return std::make_shared<SkyWcs>(*metadata);
519 auto frameDict = makeSkyWcsFrameDict(pixelsToFieldAngle, orientation, flipX, boresight, projection);
520 return std::make_shared<SkyWcs>(frameDict);
524 Eigen::Matrix2d
const& cdMatrix, Eigen::MatrixXd
const& sipA,
525 Eigen::MatrixXd
const& sipB) {
527 return std::make_shared<SkyWcs>(*metadata);
531 Eigen::Matrix2d
const& cdMatrix, Eigen::MatrixXd
const& sipA,
532 Eigen::MatrixXd
const& sipB, Eigen::MatrixXd
const& sipAp,
533 Eigen::MatrixXd
const& sipBp) {
535 return std::make_shared<SkyWcs>(*metadata);
540 auto iwcToSky = wcs.
getFrameDict()->getMapping(
"IWC",
"SKY");
541 return std::make_shared<TransformPoint2ToSpherePoint>(*iwcToSky, simplify);
546 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.
ItemVariant const * other
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::shared_ptr< RecordT > src
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.
constexpr double asArcseconds() const noexcept
Return an Angle's value in arcseconds.
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.
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.
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.
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
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.
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.