LSSTApplications  17.0+11,17.0+34,17.0+56,17.0+57,17.0+59,17.0+7,17.0-1-g377950a+33,17.0.1-1-g114240f+2,17.0.1-1-g4d4fbc4+28,17.0.1-1-g55520dc+49,17.0.1-1-g5f4ed7e+52,17.0.1-1-g6dd7d69+17,17.0.1-1-g8de6c91+11,17.0.1-1-gb9095d2+7,17.0.1-1-ge9fec5e+5,17.0.1-1-gf4e0155+55,17.0.1-1-gfc65f5f+50,17.0.1-1-gfc6fb1f+20,17.0.1-10-g87f9f3f+1,17.0.1-11-ge9de802+16,17.0.1-16-ga14f7d5c+4,17.0.1-17-gc79d625+1,17.0.1-17-gdae4c4a+8,17.0.1-2-g26618f5+29,17.0.1-2-g54f2ebc+9,17.0.1-2-gf403422+1,17.0.1-20-g2ca2f74+6,17.0.1-23-gf3eadeb7+1,17.0.1-3-g7e86b59+39,17.0.1-3-gb5ca14a,17.0.1-3-gd08d533+40,17.0.1-30-g596af8797,17.0.1-4-g59d126d+4,17.0.1-4-gc69c472+5,17.0.1-6-g5afd9b9+4,17.0.1-7-g35889ee+1,17.0.1-7-gc7c8782+18,17.0.1-9-gc4bbfb2+3,w.2019.22
LSSTDataManagementBasePackage
SkyWcs.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2017 AURA/LSST.
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <http://www.lsstcorp.org/LegalNotices/>.
21  */
22 
23 #include <algorithm>
24 #include <cmath>
25 #include <cstdint>
26 #include <exception>
27 #include <memory>
28 #include <ostream>
29 #include <sstream>
30 #include <vector>
31 
32 #include "astshim.h"
33 
34 #include "lsst/geom/Angle.h"
35 #include "lsst/geom/Point.h"
36 #include "lsst/geom/SpherePoint.h"
38 #include "lsst/afw/table.h"
43 #include "lsst/afw/geom/wcsUtils.h"
44 #include "lsst/afw/geom/SkyWcs.h"
46 #include "lsst/pex/exceptions.h"
47 #include "lsst/afw/table/io/Persistable.cc"
48 
49 namespace lsst {
50 namespace afw {
51 
54 
55 namespace geom {
56 namespace {
57 
58 int const SERIALIZATION_VERSION = 1;
59 
60 // TIGHT_FITS_TOL is used by getFitsMetadata to determine if a WCS can accurately be represented as a FITS
61 // WCS. It specifies the maximum departure from linearity (in pixels) allowed on either axis of the mapping
62 // from pixel coordinates to Intermediate World Coordinates over a range of 100 x 100 pixels
63 // (or the region specified by NAXIS[12], if provided, but we do not pass this to AST as of 2018-01-17).
64 // For more information,
65 // see FitsTol in the AST manual http://starlink.eao.hawaii.edu/devdocs/sun211.htx/sun211.html
66 double const TIGHT_FITS_TOL = 0.0001;
67 
68 class SkyWcsPersistenceHelper {
69 public:
70  table::Schema schema;
71  table::Key<table::Array<std::uint8_t>> wcs;
72 
73  static SkyWcsPersistenceHelper const& get() {
74  static SkyWcsPersistenceHelper instance;
75  return instance;
76  }
77 
78  // No copying
79  SkyWcsPersistenceHelper(const SkyWcsPersistenceHelper&) = delete;
80  SkyWcsPersistenceHelper& operator=(const SkyWcsPersistenceHelper&) = delete;
81 
82  // No moving
83  SkyWcsPersistenceHelper(SkyWcsPersistenceHelper&&) = delete;
84  SkyWcsPersistenceHelper& operator=(SkyWcsPersistenceHelper&&) = delete;
85 
86 private:
87  SkyWcsPersistenceHelper()
88  : schema(),
89  wcs(schema.addField<table::Array<std::uint8_t>>("wcs", "wcs string representation", "")) {
90  schema.getCitizen().markPersistent();
91  }
92 };
93 
94 class SkyWcsFactory : public table::io::PersistableFactory {
95 public:
96  explicit SkyWcsFactory(std::string const& name) : table::io::PersistableFactory(name) {}
97 
98  std::shared_ptr<table::io::Persistable> read(InputArchive const& archive,
99  CatalogVector const& catalogs) const override {
100  SkyWcsPersistenceHelper const& keys = SkyWcsPersistenceHelper::get();
101  LSST_ARCHIVE_ASSERT(catalogs.size() == 1u);
102  LSST_ARCHIVE_ASSERT(catalogs.front().size() == 1u);
103  LSST_ARCHIVE_ASSERT(catalogs.front().getSchema() == keys.schema);
104  table::BaseRecord const& record = catalogs.front().front();
105  std::string stringRep = formatters::bytesToString(record.get(keys.wcs));
106  return SkyWcs::readString(stringRep);
107  }
108 };
109 
110 std::string getSkyWcsPersistenceName() { return "SkyWcs"; }
111 
112 SkyWcsFactory registration(getSkyWcsPersistenceName());
113 
114 ast::FrameDict makeSkyWcsFrameDict(TransformPoint2ToPoint2 const& pixelsToFieldAngle,
115  lsst::geom::Angle const& orientation, bool flipX,
117  std::string const& projection = "TAN") {
118  auto const orientationAndFlipXMatrix = makeCdMatrix(1 * lsst::geom::degrees, orientation, flipX);
119  auto const initialWcs = makeSkyWcs(lsst::geom::Point2D(0, 0), crval, orientationAndFlipXMatrix, projection);
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");
125  // Field angle is in radians and is aligned to focal plane x and y;
126  // IWC is basically the same thing, but in degrees and with rotation and flipX applied
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;
135 }
136 
137 } // namespace
138 
140  bool flipX) {
141  Eigen::Matrix2d cdMatrix;
142  double orientRad = orientation.asRadians();
143  double scaleDeg = scale.asDegrees();
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;
149  return cdMatrix;
150 }
151 
153  auto const dstInverse = dst.getTransform()->inverted();
154  return src.getTransform()->then(*dstInverse);
155 }
156 
157 SkyWcs::SkyWcs(daf::base::PropertySet& metadata, bool strip)
158  : SkyWcs(detail::readLsstSkyWcs(metadata, strip)) {}
159 
160 SkyWcs::SkyWcs(ast::FrameDict const& frameDict) : SkyWcs(_checkFrameDict(frameDict)) {}
161 
162 bool SkyWcs::operator==(SkyWcs const& other) const { return writeString() == other.writeString(); }
163 
165  // Compute pixVec containing the pixel position and two nearby points
166  // (use a vector so all three points can be converted to sky in a single call)
167  double const side = 1.0;
169  pixel, pixel + lsst::geom::Extent2D(side, 0), pixel + lsst::geom::Extent2D(0, side),
170  };
171 
172  auto skyVec = pixelToSky(pixVec);
173 
174  // Work in 3-space to avoid RA wrapping and pole issues
175  auto skyLL = skyVec[0].getVector();
176  auto skyDx = skyVec[1].getVector() - skyLL;
177  auto skyDy = skyVec[2].getVector() - skyLL;
178 
179  // Compute pixel scale in radians = sqrt(pixel area in radians^2)
180  // pixel area in radians^2 = area of parallelogram with sides skyDx, skyDy = |skyDx cross skyDy|
181  // Use squared norm to avoid two square roots
182  double skyAreaSq = skyDx.cross(skyDy).getSquaredNorm();
183  return (std::pow(skyAreaSq, 0.25) / side) * lsst::geom::radians;
184 }
185 
187  // CRVAL is stored as the SkyRef property of the sky frame (the current frame of the SkyWcs)
189  getFrameDict()->getFrame(ast::FrameDict::CURRENT, false)); // false: do not copy
190  if (!skyFrame) {
191  throw LSST_EXCEPT(pex::exceptions::LogicError, "Current frame is not a SkyFrame");
192  }
193  auto const crvalRad = skyFrame->getSkyRef();
194  return lsst::geom::SpherePoint(crvalRad[0] * lsst::geom::radians, crvalRad[1] * lsst::geom::radians);
195 }
196 
197 Eigen::Matrix2d SkyWcs::getCdMatrix(lsst::geom::Point2D const& pixel) const {
198  auto const pixelToIwc = getFrameDict()->getMapping(ast::FrameSet::BASE, "IWC");
199  auto const pixelToIwcTransform = TransformPoint2ToPoint2(*pixelToIwc);
200  return pixelToIwcTransform.getJacobian(pixel);
201 }
202 
203 Eigen::Matrix2d SkyWcs::getCdMatrix() const { return getCdMatrix(getPixelOrigin()); }
204 
206  auto const crval = pixelToSky(pixel);
207  auto const cdMatrix = getCdMatrix(pixel);
208  auto metadata = makeSimpleWcsMetadata(pixel, crval, cdMatrix);
209  return std::make_shared<SkyWcs>(*metadata);
210 }
211 
213  auto newToOldPixel = TransformPoint2ToPoint2(ast::ShiftMap({-shift[0], -shift[1]}));
214  return makeModifiedWcs(newToOldPixel, *this, true);
215 }
216 
218  // Make a FrameSet that maps from GRID to SKY; GRID = the base frame (PIXELS or ACTUAL_PIXELS) + 1
219  auto const gridToPixel = ast::ShiftMap({-1.0, -1.0});
220  auto thisDict = getFrameDict();
221  auto const pixelToIwc = thisDict->getMapping(ast::FrameSet::BASE, "IWC");
222  auto const iwcToSky = thisDict->getMapping("IWC", "SKY");
223  auto const gridToSky = gridToPixel.then(*pixelToIwc).then(*iwcToSky);
224  ast::FrameSet frameSet(ast::Frame(2, "Domain=GRID"), gridToSky, *thisDict->getFrame("SKY", false));
225 
226  // Write frameSet to a FitsChan and extract the metadata
228  os << "Encoding=FITS-WCS, CDMatrix=1, FitsAxisOrder=<copy>, FitsTol=" << TIGHT_FITS_TOL;
229  ast::StringStream strStream;
230  ast::FitsChan fitsChan(strStream, os.str());
231  int const nObjectsWritten = fitsChan.write(frameSet);
232  if (nObjectsWritten == 0) {
233  if (precise) {
235  "Could not represent this SkyWcs using FITS-WCS metadata");
236  } else {
237  // An exact representation could not be written, so try to write a local TAN approximation;
238  // set precise true to avoid an infinite loop, should something go wrong
239  auto tanWcs = getTanWcs(getPixelOrigin());
240  return tanWcs->getFitsMetadata(true);
241  }
242  }
244 }
245 
247 
248 bool SkyWcs::isFits() const {
249  try {
250  getFitsMetadata(true);
251  } catch (const lsst::pex::exceptions::RuntimeError&) {
252  return false;
253  } catch (const std::runtime_error&) {
254  return false;
255  }
256  return true;
257 }
258 
260  lsst::geom::AngleUnit const& skyUnit) const {
261  return _linearizePixelToSky(skyToPixel(coord), coord, skyUnit);
262 }
264  lsst::geom::AngleUnit const& skyUnit) const {
265  return _linearizePixelToSky(pix, pixelToSky(pix), skyUnit);
266 }
267 
269  lsst::geom::AngleUnit const& skyUnit) const {
270  return _linearizeSkyToPixel(skyToPixel(coord), coord, skyUnit);
271 }
272 
274  lsst::geom::AngleUnit const& skyUnit) const {
275  return _linearizeSkyToPixel(pix, pixelToSky(pix), skyUnit);
276 }
277 
278 std::string SkyWcs::getShortClassName() { return "SkyWcs"; };
279 
280 bool SkyWcs::isFlipped() const {
281  double det = getCdMatrix().determinant();
282  if (det == 0) {
283  throw(LSST_EXCEPT(pex::exceptions::RuntimeError, "CD matrix is singular"));
284  }
285  return (det > 0);
286 }
287 
289  int version;
290  is >> version;
291  if (version != 1) {
292  throw LSST_EXCEPT(pex::exceptions::TypeError, "Unsupported version " + std::to_string(version));
293  }
294  std::string shortClassName;
295  is >> shortClassName;
296  if (shortClassName != SkyWcs::getShortClassName()) {
298  os << "Class name in stream " << shortClassName << " != " << SkyWcs::getShortClassName();
300  }
302  is >> hasFitsApproximation;
303  auto astStream = ast::Stream(&is, nullptr);
304  auto astObjectPtr = ast::Channel(astStream).read();
305  auto frameSet = std::dynamic_pointer_cast<ast::FrameSet>(astObjectPtr);
306  if (!frameSet) {
308  os << "The AST serialization was read as a " << astObjectPtr->getClassName()
309  << " instead of a FrameSet";
311  }
313  return std::make_shared<SkyWcs>(frameDict);
314 }
315 
317  std::istringstream is(str);
318  return SkyWcs::readStream(is);
319 }
320 
322  os << SERIALIZATION_VERSION << " " << SkyWcs::getShortClassName() << " " << hasFitsApproximation() << " ";
323  getFrameDict()->show(os, false); // false = do not write comments
324 }
325 
328  writeStream(os);
329  return os.str();
330 }
331 
333  return std::make_unique<SkyWcs>(*this);
334 }
335 
336 std::string SkyWcs::toString() const { return "SkyWcs"; }
337 
338 bool SkyWcs::equals(typehandling::Storable const& other) const noexcept {
339  return singleClassEquals(*this, other);
340 }
341 
342 std::string SkyWcs::getPersistenceName() const { return getSkyWcsPersistenceName(); }
343 
344 std::string SkyWcs::getPythonModule() const { return "lsst.afw.geom"; }
345 
346 void SkyWcs::write(OutputArchiveHandle& handle) const {
347  SkyWcsPersistenceHelper const& keys = SkyWcsPersistenceHelper::get();
348  table::BaseCatalog cat = handle.makeCatalog(keys.schema);
350  record->set(keys.wcs, formatters::stringToBytes(writeString()));
351  handle.saveCatalog(cat);
352 }
353 
355  : _frameDict(frameDict), _transform(), _pixelOrigin(), _pixelScaleAtOrigin(0 * lsst::geom::radians) {
356  _computeCache();
357 };
358 
359 std::shared_ptr<ast::FrameDict> SkyWcs::_checkFrameDict(ast::FrameDict const& frameDict) const {
360  // Check that each frame is present and has the right type and number of axes
361  std::vector<std::string> const domainNames = {"ACTUAL_PIXELS", "PIXELS", "IWC", "SKY"};
362  for (auto const& domainName : domainNames) {
363  if (frameDict.hasDomain(domainName)) {
364  auto const frame = frameDict.getFrame(domainName, false);
365  if (frame->getNAxes() != 2) {
367  "Frame " + domainName + " has " + std::to_string(frame->getNAxes()) +
368  " axes instead of 2");
369  }
370  auto desiredClassName = domainName == "SKY" ? "SkyFrame" : "Frame";
371  if (frame->getClassName() != desiredClassName) {
373  "Frame " + domainName + " is of type " + frame->getClassName() +
374  " instead of " + desiredClassName);
375  }
376  } else if (domainName != "ACTUAL_PIXELS") {
377  // This is a required frame
379  "No frame with domain " + domainName + " found");
380  }
381  }
382 
383  // The base frame must have domain "PIXELS" or "ACTUAL_PIXELS"
384  auto baseDomain = frameDict.getFrame(ast::FrameSet::BASE, false)->getDomain();
385  if (baseDomain != "ACTUAL_PIXELS" && baseDomain != "PIXELS") {
387  "Base frame has domain " + baseDomain + " instead of PIXELS or ACTUAL_PIXELS");
388  }
389 
390  // The current frame must have domain "SKY"
391  auto currentDomain = frameDict.getFrame(ast::FrameSet::CURRENT, false)->getDomain();
392  if (currentDomain != "SKY") {
394  "Current frame has domain " + currentDomain + " instead of SKY");
395  }
396 
397  return frameDict.copy();
398 }
399 
400 lsst::geom::AffineTransform SkyWcs::_linearizePixelToSky(lsst::geom::Point2D const& pix00,
401  lsst::geom::SpherePoint const& coord,
402  lsst::geom::AngleUnit const& skyUnit) const {
403  // Figure out the (0, 0), (0, 1), and (1, 0) ra/dec coordinates of the corners
404  // of a square drawn in pixel. It'd be better to center the square at sky00,
405  // but that would involve another conversion between sky and pixel coordinates
406  const double side = 1.0; // length of the square's sides in pixels
407  auto const sky00 = coord.getPosition(skyUnit);
408  auto const dsky10 = coord.getTangentPlaneOffset(pixelToSky(pix00 + lsst::geom::Extent2D(side, 0)));
409  auto const dsky01 = coord.getTangentPlaneOffset(pixelToSky(pix00 + lsst::geom::Extent2D(0, side)));
410 
411  Eigen::Matrix2d m;
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;
416 
417  Eigen::Vector2d sky00v;
418  sky00v << sky00.getX(), sky00.getY();
419  Eigen::Vector2d pix00v;
420  pix00v << pix00.getX(), pix00.getY();
421  // return lsst::geom::AffineTransform(m, lsst::geom::Extent2D(sky00v - m * pix00v));
422  return lsst::geom::AffineTransform(m, (sky00v - m * pix00v));
423 }
424 
425 lsst::geom::AffineTransform SkyWcs::_linearizeSkyToPixel(lsst::geom::Point2D const& pix00,
426  lsst::geom::SpherePoint const& coord,
427  lsst::geom::AngleUnit const& skyUnit) const {
428  lsst::geom::AffineTransform inverse = _linearizePixelToSky(pix00, coord, skyUnit);
429  return inverse.inverted();
430 }
431 
432 std::shared_ptr<SkyWcs> makeFlippedWcs(SkyWcs const& wcs, bool flipLR, bool flipTB,
433  lsst::geom::Point2D const& center) {
434  double const dx = 1000; // any "reasonable" number of pixels will do
435  std::vector<double> inLL = {center[0] - dx, center[1] - dx};
436  std::vector<double> inUR = {center[0] + dx, center[1] + dx};
437  std::vector<double> outLL(inLL);
438  std::vector<double> outUR(inUR);
439  if (flipLR) {
440  outLL[0] = inUR[0];
441  outUR[0] = inLL[0];
442  }
443  if (flipTB) {
444  outLL[1] = inUR[1];
445  outUR[1] = inLL[1];
446  }
447  auto const flipPix = TransformPoint2ToPoint2(ast::WinMap(inLL, inUR, outLL, outUR));
448  return makeModifiedWcs(flipPix, wcs, true);
449 }
450 
452  bool modifyActualPixels) {
453  auto const pixelMapping = pixelTransform.getMapping();
454  auto oldFrameDict = wcs.getFrameDict();
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");
461 
462  std::shared_ptr<ast::FrameDict> newFrameDict;
463  std::shared_ptr<ast::Mapping> newPixelToIwc;
464  if (hasActualPixels) {
465  auto const actualPixelFrame = oldFrameDict->getFrame("ACTUAL_PIXELS", false);
466  auto const oldActualPixelToPixels = oldFrameDict->getMapping("ACTUAL_PIXELS", "PIXELS");
467  std::shared_ptr<ast::Mapping> newActualPixelsToPixels;
468  if (modifyActualPixels) {
469  newActualPixelsToPixels = pixelMapping->then(*oldActualPixelToPixels).simplified();
470  newPixelToIwc = oldPixelToIwc;
471  } else {
472  newActualPixelsToPixels = oldActualPixelToPixels;
473  newPixelToIwc = pixelMapping->then(*oldPixelToIwc).simplified();
474  }
475  newFrameDict =
476  std::make_shared<ast::FrameDict>(*actualPixelFrame, *newActualPixelsToPixels, *pixelFrame);
477  newFrameDict->addFrame("PIXELS", *newPixelToIwc, *iwcFrame);
478  } else {
479  newPixelToIwc = pixelMapping->then(*oldPixelToIwc).simplified();
480  newFrameDict = std::make_shared<ast::FrameDict>(*pixelFrame, *newPixelToIwc, *iwcFrame);
481  }
482  newFrameDict->addFrame("IWC", *iwcToSky, *skyFrame);
483  return std::make_shared<SkyWcs>(*newFrameDict);
484 }
485 
487  return std::make_shared<SkyWcs>(metadata, strip);
488 }
489 
491  Eigen::Matrix2d const& cdMatrix, std::string const& projection) {
492  auto metadata = makeSimpleWcsMetadata(crpix, crval, cdMatrix, projection);
493  return std::make_shared<SkyWcs>(*metadata);
494 }
495 
497  lsst::geom::Angle const& orientation, bool flipX,
498  lsst::geom::SpherePoint const& boresight, std::string const& projection) {
499  auto frameDict = makeSkyWcsFrameDict(pixelsToFieldAngle, orientation, flipX, boresight, projection);
500  return std::make_shared<SkyWcs>(frameDict);
501 }
502 
504  Eigen::Matrix2d const& cdMatrix, Eigen::MatrixXd const& sipA,
505  Eigen::MatrixXd const& sipB) {
506  auto metadata = makeTanSipMetadata(crpix, crval, cdMatrix, sipA, sipB);
507  return std::make_shared<SkyWcs>(*metadata);
508 }
509 
511  Eigen::Matrix2d const& cdMatrix, Eigen::MatrixXd const& sipA,
512  Eigen::MatrixXd const& sipB, Eigen::MatrixXd const& sipAp,
513  Eigen::MatrixXd const& sipBp) {
514  auto metadata = makeTanSipMetadata(crpix, crval, cdMatrix, sipA, sipB, sipAp, sipBp);
515  return std::make_shared<SkyWcs>(*metadata);
516 }
517 
519  bool simplify) {
520  auto iwcToSky = wcs.getFrameDict()->getMapping("IWC", "SKY");
521  return std::make_shared<TransformPoint2ToSpherePoint>(*iwcToSky, simplify);
522 }
523 
525  auto pixelToIwc = wcs.getFrameDict()->getMapping(ast::FrameSet::BASE, "IWC");
526  return std::make_shared<TransformPoint2ToPoint2>(*pixelToIwc, simplify);
527 }
528 
530  os << wcs.toString();
531  return os;
532 };
533 
534 } // namespace geom
535 } // namespace afw
536 } // namespace lsst
table::Key< table::Array< std::uint8_t > > frameSet
std::pair< Angle, Angle > getTangentPlaneOffset(SpherePoint const &other) const
Get the offset from a tangent plane centered at this point to another point.
Definition: SpherePoint.cc:214
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
Definition: Persistable.cc:18
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
Definition: SkyWcs.h:117
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.
Definition: SkyWcs.cc:205
constexpr double asRadians() const noexcept
Return an Angle&#39;s value in radians.
Definition: Angle.h:166
MatrixMap is a form of Mapping which performs a general linear transformation.
Definition: MatrixMap.h:42
constexpr double asDegrees() const noexcept
Return an Angle&#39;s value in degrees.
Definition: Angle.h:169
lsst::geom::Point2D skyToPixel(lsst::geom::SpherePoint const &sky) const
Compute pixel position(s) from sky position(s)
Definition: SkyWcs.h:349
An object passed to Persistable::write to allow it to persist itself.
An affine coordinate transformation consisting of a linear transformation and an offset.
lsst::geom::SpherePoint pixelToSky(lsst::geom::Point2D const &pixel) const
Compute sky position(s) from pixel position(s)
Definition: SkyWcs.h:334
std::shared_ptr< const ast::Mapping > getMapping() const
Get the contained mapping.
Definition: Transform.h:135
bool isFits() const
Return true getFitsMetadata(true) will succeed, false if not.
Definition: SkyWcs.cc:248
table::PointKey< double > crpix
Definition: OldWcs.cc:131
Interface supporting iteration over heterogenous containers.
Definition: Storable.h:56
Point2D getPosition(AngleUnit unit) const noexcept
Return longitude, latitude as a Point2D object.
Definition: SpherePoint.cc:129
def scale(algorithm, min, max=None, frame=None)
Definition: ds9.py:109
T to_string(T... args)
Channel provides input/output of AST objects.
Definition: Channel.h:60
SeriesMap then(Mapping const &next) const
Return a series compound mapping this(first(input)) containing shallow copies of the original...
Definition: Mapping.cc:37
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.
Definition: SkyWcs.cc:451
std::string getPythonModule() const override
Return the fully-qualified Python module that should be imported to guarantee that its factory is reg...
Definition: SkyWcs.cc:344
table::PointKey< double > crval
Definition: OldWcs.cc:130
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.
Definition: SkyWcs.cc:186
static int constexpr CURRENT
index of current frame
Definition: FrameSet.h:105
bool equals(typehandling::Storable const &other) const noexcept override
Compare this object to another Storable.
Definition: SkyWcs.cc:338
std::string bytesToString(ndarray::Array< std::uint8_t const, 1, 1 > const &bytes)
Decode a std::string from a vector of uint8 returned by stringToBytes.
Definition: Utils.cc:173
STL class.
std::shared_ptr< const ast::FrameDict > getFrameDict() const
Get the contained FrameDict.
Definition: SkyWcs.cc:246
AngleUnit constexpr radians
constant with units of radians
Definition: Angle.h:108
A class representing an angle.
Definition: Angle.h:127
A specialized form of Channel which reads and writes FITS header cards.
Definition: FitsChan.h:201
table::Key< table::Array< std::uint8_t > > wcs
Definition: SkyWcs.cc:71
Transform< Point2Endpoint, Point2Endpoint > TransformPoint2ToPoint2
Definition: Transform.h:300
STL class.
T sin(T... args)
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
Definition: SkyWcs.cc:342
A WinMap is a linear Mapping which transforms a rectangular window in one coordinate system into a si...
Definition: WinMap.h:45
Eigen::Matrix2d getCdMatrix() const
Get the 2x2 CD matrix at the pixel origin.
Definition: SkyWcs.cc:203
std::shared_ptr< const TransformPoint2ToSpherePoint > getTransform() const
Get a TransformPoint2ToSpherePoint that transforms pixels to sky in the forward direction and sky to ...
Definition: SkyWcs.h:257
AngleUnit constexpr degrees
constant with units of degrees
Definition: Angle.h:109
SkyFrame is a specialised form of Frame which describes celestial longitude/latitude coordinate syste...
Definition: SkyFrame.h:66
A base class for image defects.
bool hasFitsApproximation() const
Does this SkyWcs have an approximate SkyWcs that can be represented as standard FITS WCS...
Definition: SkyWcs.h:364
std::shared_ptr< SkyWcs > makeFlippedWcs(SkyWcs const &wcs, bool flipLR, bool flipTB, lsst::geom::Point2D const &center)
Return a copy of a FITS-WCS with pixel positions flipped around a specified center.
Definition: SkyWcs.cc:432
Frame is used to represent a coordinate system.
Definition: Frame.h:157
std::string toString() const override
Create a string representation of this object.
Definition: SkyWcs.cc:336
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.
Definition: FrameDict.h:151
std::shared_ptr< FrameDict > copy() const
Return a deep copy of this object.
Definition: FrameDict.h:123
static std::shared_ptr< SkyWcs > readStream(std::istream &is)
Deserialize a SkyWcs from an input stream.
Definition: SkyWcs.cc:288
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.
Definition: SkyWcs.cc:259
T str(T... args)
std::shared_ptr< daf::base::PropertyList > getPropertyListFromFitsChan(ast::FitsChan &fitsChan)
Copy values from an AST FitsChan into a PropertyList.
T cos(T... args)
T dynamic_pointer_cast(T... args)
static std::string getShortClassName()
Definition: SkyWcs.cc:278
std::shared_ptr< TransformPoint2ToPoint2 > getPixelToIntermediateWorldCoords(SkyWcs const &wcs, bool simplify=true)
Return a transform from pixel coordinates to intermediate world coordinates.
Definition: SkyWcs.cc:524
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.
Definition: SkyWcs.cc:503
std::shared_ptr< TransformPoint2ToSpherePoint > getIntermediateWorldCoordsToSky(SkyWcs const &wcs, bool simplify=true)
Return a transform from intermediate world coordinates to sky.
Definition: SkyWcs.cc:518
Reports errors in the logical structure of the program.
Definition: Runtime.h:46
ShiftMap is a linear Mapping which shifts each axis by a specified constant value.
Definition: ShiftMap.h:40
std::shared_ptr< typehandling::Storable > cloneStorable() const override
Create a new SkyWcs that is a copy of this one.
Definition: SkyWcs.cc:332
std::shared_ptr< RecordT > src
Definition: Match.cc:48
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.
Definition: Storable.h:159
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.
Definition: wcsUtils.cc:198
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.
Definition: SkyWcs.cc:212
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
Definition: SkyWcs.cc:152
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
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).
Definition: wcsUtils.cc:172
STL class.
Point in an unspecified spherical coordinate system.
Definition: SpherePoint.h:57
static std::shared_ptr< SkyWcs > readString(std::string &str)
Deserialize a SkyWcs from a string, using the same format as readStream.
Definition: SkyWcs.cc:316
lsst::geom::Point2D getPixelOrigin() const
Get the pixel origin, in pixels, using the LSST convention.
Definition: SkyWcs.h:215
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
Definition: SkyWcs.cc:346
T pow(T... args)
SkyWcs(SkyWcs const &)=default
Class for storing generic metadata.
Definition: PropertySet.h:68
std::string writeString() const
Serialize this SkyWcs to a string, using the same format as writeStream.
Definition: SkyWcs.cc:326
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
Definition: SkyWcs.cc:486
std::shared_ptr< daf::base::PropertyList > getFitsMetadata(bool precise=false) const
Return the WCS as FITS WCS metadata.
Definition: SkyWcs.cc:217
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.
Definition: SkyWcs.cc:139
String-based source and sink for channels.
Definition: Stream.h:180
int m
Definition: SpanSet.cc:49
lsst::geom::SpherePoint SpherePoint
Definition: misc.h:35
table::PointKey< int > pixel
void writeStream(std::ostream &os) const
Serialize this SkyWcs to an output stream.
Definition: SkyWcs.cc:321
ItemVariant const * other
Definition: Schema.cc:56
static int constexpr BASE
index of base frame
Definition: FrameSet.h:104
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
table::Key< int > version
Definition: PhotoCalib.cc:402
bool isFlipped() const
Does the WCS follow the convention of North=Up, East=Left?
Definition: SkyWcs.cc:280
ndarray::Array< std::uint8_t, 1, 1 > stringToBytes(std::string const &str)
Encode a std::string as a vector of uint8.
Definition: Utils.cc:162
Extent< double, 2 > Extent2D
Definition: Extent.h:400
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.
Definition: SkyWcs.cc:268
table::Schema schema
Definition: SkyWcs.cc:70
Reports errors from accepting an object of an unexpected or inappropriate type.
Definition: Runtime.h:167
lsst::geom::Angle getPixelScale() const
Get the pixel scale at the pixel origin.
Definition: SkyWcs.h:208
A FrameSet whose frames can be referenced by domain name.
Definition: FrameDict.h:67
STL class.
bool operator==(SkyWcs const &other) const
Equality is based on the string representations being equal.
Definition: SkyWcs.cc:162
AffineTransform const inverted() const
Return the inverse transform.
std::shared_ptr< Object > read()
Read an object from a channel.
Definition: Channel.cc:52
A stream for ast::Channel.
Definition: Stream.h:41
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).
Definition: FrameSet.h:99
double constexpr PI
The ratio of a circle&#39;s circumference to diameter.
Definition: Angle.h:39
bool strip
Definition: fits.cc:883
A class used to convert scalar POD types such as double to Angle.
Definition: Angle.h:70
std::ostream * os
Definition: Schema.cc:746
Transform LSST spatial data, such as lsst::geom::Point2D and lsst::geom::SpherePoint, using an AST mapping.
Definition: Transform.h:67
bool hasDomain(std::string const &domain) const
Return True if a frame in this FrameDict has the specified domain.
Definition: FrameDict.h:201
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
Definition: Catalog.h:485
static bool singleClassEquals(T const &lhs, Storable const &rhs)
Test if a Storable is of a particular class and equal to another object.
Definition: Storable.h:136