LSSTApplications  15.0+21,16.0+1,16.0+3,16.0+4,16.0+8,16.0-1-g2115a9e+2,16.0-1-g4515a79+6,16.0-1-g5c6f5ee+4,16.0-1-g7bb14cc,16.0-1-g80120d7+4,16.0-1-g98efed3+4,16.0-1-gb7f560d+1,16.0-14-gb4f0cd2fa,16.0-2-g1ad129e+1,16.0-2-g2ed7261+1,16.0-2-g311bfd2,16.0-2-g568a347+3,16.0-2-g852da13+6,16.0-2-gd4c87cb+3,16.0-3-g099ede0,16.0-3-g150e024+3,16.0-3-g1f513a6,16.0-3-g958ce35,16.0-4-g08dccf71+4,16.0-4-g128aaef,16.0-4-g84f75fb+5,16.0-4-gcfd1396+4,16.0-4-gde8cee2,16.0-4-gdfb0d14+1,16.0-5-g7bc0afb+3,16.0-5-g86fb31a+3,16.0-6-g2dd73041+4,16.0-7-g95fb7bf,16.0-7-gc37dbc2+4,w.2018.28
LSSTDataManagementBasePackage
Transform.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2008-2017 LSST Corporation.
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 <exception>
24 #include <memory>
25 #include <ostream>
26 #include <sstream>
27 #include <vector>
28 
29 #include "astshim.h"
32 #include "lsst/afw/geom/Endpoint.h"
34 #include "lsst/afw/geom/SkyWcs.h"
38 
39 namespace lsst {
40 namespace afw {
41 namespace geom {
42 
43 template <class FromEndpoint, class ToEndpoint>
45  : _fromEndpoint(mapping.getNIn()),
46  _mapping(simplify ? mapping.simplify() : mapping.copy()),
47  _toEndpoint(mapping.getNOut()) {}
48 
49 template <typename FromEndpoint, typename ToEndpoint>
51  : _fromEndpoint(frameSet.getNIn()), _mapping(), _toEndpoint(frameSet.getNOut()) {
52  auto frameSetCopy = frameSet.copy();
53  // Normalize the base and current frame in a way that affects its behavior as a mapping.
54  // To do this one must set the current frame to the frame to be normalized
55  // and normalize the frame set as a frame (i.e. normalize the frame "in situ").
56  // The obvious alternative of normalizing a shallow copy of the frame does not work;
57  // the frame is altered but not the associated mapping!
58 
59  // Normalize the current frame by normalizing the frameset as a frame
60  _toEndpoint.normalizeFrame(frameSetCopy);
61 
62  // Normalize the base frame by temporarily making it the current frame,
63  // normalizing the frameset as a frame, then making it the base frame again
64  const int baseIndex = frameSetCopy->getBase();
65  const int currentIndex = frameSetCopy->getCurrent();
66  frameSetCopy->setCurrent(baseIndex);
67  _fromEndpoint.normalizeFrame(frameSetCopy);
68  frameSetCopy->setBase(baseIndex);
69  frameSetCopy->setCurrent(currentIndex);
70  _mapping = simplify ? frameSetCopy->getMapping()->simplify() : frameSetCopy->getMapping();
71 }
72 
73 template <typename FromEndpoint, typename ToEndpoint>
75  : _fromEndpoint(mapping->getNIn()), _mapping(mapping), _toEndpoint(mapping->getNOut()) {}
76 
77 template <class FromEndpoint, class ToEndpoint>
79  typename FromEndpoint::Point const &point) const {
80  auto const rawFromData = _fromEndpoint.dataFromPoint(point);
81  auto rawToData = _mapping->applyForward(rawFromData);
82  return _toEndpoint.pointFromData(rawToData);
83 }
84 
85 template <class FromEndpoint, class ToEndpoint>
87  typename FromEndpoint::Array const &array) const {
88  auto const rawFromData = _fromEndpoint.dataFromArray(array);
89  auto rawToData = _mapping->applyForward(rawFromData);
90  return _toEndpoint.arrayFromData(rawToData);
91 }
92 
93 template <class FromEndpoint, class ToEndpoint>
95  typename ToEndpoint::Point const &point) const {
96  auto const rawFromData = _toEndpoint.dataFromPoint(point);
97  auto rawToData = _mapping->applyInverse(rawFromData);
98  return _fromEndpoint.pointFromData(rawToData);
99 }
100 
101 template <class FromEndpoint, class ToEndpoint>
103  typename ToEndpoint::Array const &array) const {
104  auto const rawFromData = _toEndpoint.dataFromArray(array);
105  auto rawToData = _mapping->applyInverse(rawFromData);
106  return _fromEndpoint.arrayFromData(rawToData);
107 }
108 
109 template <class FromEndpoint, class ToEndpoint>
111  auto inverse = std::dynamic_pointer_cast<ast::Mapping>(_mapping->getInverse());
112  if (!inverse) {
113  // don't throw std::bad_cast because it doesn't let you provide debugging info
114  std::ostringstream buffer;
115  buffer << "Mapping.getInverse() does not return a Mapping. Called from: " << _mapping;
117  }
118  return std::make_shared<Transform<ToEndpoint, FromEndpoint>>(*inverse);
119 }
120 
121 template <class FromEndpoint, class ToEndpoint>
123  int const nIn = _fromEndpoint.getNAxes();
124  int const nOut = _toEndpoint.getNAxes();
125  std::vector<double> const point = _fromEndpoint.dataFromPoint(x);
126 
127  Eigen::MatrixXd jacobian(nOut, nIn);
128  for (int i = 0; i < nOut; ++i) {
129  for (int j = 0; j < nIn; ++j) {
130  jacobian(i, j) = _mapping->rate(point, i + 1, j + 1);
131  }
132  }
133  return jacobian;
134 }
135 
136 template <class FromEndpoint, class ToEndpoint>
139  os << "Transform" << FromEndpoint::getClassPrefix() << "To" << ToEndpoint::getClassPrefix();
140  return os.str();
141 }
142 
143 template <class FromEndpoint, class ToEndpoint>
145  std::istream &is) {
146  return detail::readStream<Transform<FromEndpoint, ToEndpoint>>(is);
147 }
148 
149 template <class FromEndpoint, class ToEndpoint>
151  std::string &str) {
152  std::istringstream is(str);
154 }
155 
156 template <class FromEndpoint, class ToEndpoint>
158  detail::writeStream<Transform<FromEndpoint, ToEndpoint>>(*this, os);
159 }
160 
161 template <class FromEndpoint, class ToEndpoint>
164  writeStream(os);
165  return os.str();
166 }
167 
168 template <class FromEndpoint, class ToEndpoint>
169 template <class NextToEndpoint>
171  Transform<ToEndpoint, NextToEndpoint> const &next, bool simplify) const {
172  if (_toEndpoint.getNAxes() == next.getFromEndpoint().getNAxes()) {
173  auto nextMapping = next.getMapping();
174  auto combinedMapping = getMapping()->then(*next.getMapping());
175  if (simplify) {
176  return std::make_shared<Transform<FromEndpoint, NextToEndpoint>>(*combinedMapping.simplify());
177  } else {
178  return std::make_shared<Transform<FromEndpoint, NextToEndpoint>>(combinedMapping);
179  }
180  } else {
181  auto message = "Cannot match " + std::to_string(_toEndpoint.getNAxes()) + "-D to-endpoint to " +
182  std::to_string(next.getFromEndpoint().getNAxes()) + "-D from-endpoint.";
184  }
185 }
186 
187 template <class FromEndpoint, class ToEndpoint>
188 std::ostream &operator<<(std::ostream &os, Transform<FromEndpoint, ToEndpoint> const &transform) {
189  os << "Transform<" << transform.getFromEndpoint() << ", " << transform.getToEndpoint() << ">";
190  return os;
191 };
192 
193 namespace {
194 
195 class TransformPersistenceHelper {
196 public:
197  table::Schema schema;
198  table::Key<table::Array<std::uint8_t>> bytes;
199 
200  static TransformPersistenceHelper const &get() {
201  static TransformPersistenceHelper instance;
202  return instance;
203  }
204 
205  // No copying
206  TransformPersistenceHelper(TransformPersistenceHelper const &) = delete;
207  TransformPersistenceHelper &operator=(TransformPersistenceHelper const &) = delete;
208 
209  // No moving
210  TransformPersistenceHelper(TransformPersistenceHelper &&) = delete;
211  TransformPersistenceHelper &operator=(TransformPersistenceHelper &&) = delete;
212 
213 private:
214  TransformPersistenceHelper()
215  : schema(),
216  bytes(schema.addField<table::Array<std::uint8_t>>(
217  "bytes", "a bytestring containing the output of Transform.writeString", "")) {
218  schema.getCitizen().markPersistent();
219  }
220 };
221 
222 template <typename FromEndpoint, typename ToEndpoint>
223 class TransformFactory : public table::io::PersistableFactory {
224 public:
225  explicit TransformFactory(std::string const &name) : table::io::PersistableFactory(name) {}
226 
227  virtual std::shared_ptr<table::io::Persistable> read(InputArchive const &archive,
228  CatalogVector const &catalogs) const {
229  auto const &keys = TransformPersistenceHelper::get();
230  LSST_ARCHIVE_ASSERT(catalogs.size() == 1u);
231  LSST_ARCHIVE_ASSERT(catalogs.front().size() == 1u);
232  LSST_ARCHIVE_ASSERT(catalogs.front().getSchema() == keys.schema);
233  auto const &record = catalogs.front().front();
234  std::string stringRep = formatters::bytesToString(record.get(keys.bytes));
235  return Transform<FromEndpoint, ToEndpoint>::readString(stringRep);
236  }
237 };
238 
239 } // namespace
240 
241 template <class FromEndpoint, class ToEndpoint>
243  auto const &keys = TransformPersistenceHelper::get();
244  table::BaseCatalog cat = handle.makeCatalog(keys.schema);
246  record->set(keys.bytes, formatters::stringToBytes(writeString()));
247  handle.saveCatalog(cat);
248 }
249 
250 #define INSTANTIATE_OVERLOADS(FromEndpoint, ToEndpoint, NextToEndpoint) \
251  template std::shared_ptr<Transform<FromEndpoint, NextToEndpoint>> \
252  Transform<FromEndpoint, ToEndpoint>::then<NextToEndpoint>( \
253  Transform<ToEndpoint, NextToEndpoint> const &next, bool) const;
254 
255 #define INSTANTIATE_TRANSFORM(FromEndpoint, ToEndpoint) \
256  template class Transform<FromEndpoint, ToEndpoint>; \
257  template std::ostream &operator<<<FromEndpoint, ToEndpoint>( \
258  std::ostream &os, Transform<FromEndpoint, ToEndpoint> const &transform); \
259  namespace { \
260  TransformFactory<FromEndpoint, ToEndpoint> registration##FromEndpoint##ToEndpoint( \
261  Transform<FromEndpoint, ToEndpoint>::getShortClassName()); \
262  } \
263  INSTANTIATE_OVERLOADS(FromEndpoint, ToEndpoint, GenericEndpoint) \
264  INSTANTIATE_OVERLOADS(FromEndpoint, ToEndpoint, Point2Endpoint) \
265  INSTANTIATE_OVERLOADS(FromEndpoint, ToEndpoint, SpherePointEndpoint)
266 
267 // explicit instantiations
268 INSTANTIATE_TRANSFORM(GenericEndpoint, GenericEndpoint);
269 INSTANTIATE_TRANSFORM(GenericEndpoint, Point2Endpoint);
270 INSTANTIATE_TRANSFORM(GenericEndpoint, SpherePointEndpoint);
271 INSTANTIATE_TRANSFORM(Point2Endpoint, GenericEndpoint);
272 INSTANTIATE_TRANSFORM(Point2Endpoint, Point2Endpoint);
273 INSTANTIATE_TRANSFORM(Point2Endpoint, SpherePointEndpoint);
274 INSTANTIATE_TRANSFORM(SpherePointEndpoint, GenericEndpoint);
275 INSTANTIATE_TRANSFORM(SpherePointEndpoint, Point2Endpoint);
276 INSTANTIATE_TRANSFORM(SpherePointEndpoint, SpherePointEndpoint);
277 
278 } // namespace geom
279 } // namespace afw
280 } // namespace lsst
FromEndpoint getFromEndpoint() const
Get the "from" endpoint.
Definition: Transform.h:130
table::Key< table::Array< std::uint8_t > > bytes
Definition: Transform.cc:198
ToPoint applyForward(FromPoint const &point) const
Transform one point in the forward direction ("from" to "to")
Definition: Transform.cc:78
An object passed to Persistable::write to allow it to persist itself.
std::shared_ptr< const ast::Mapping > getMapping() const
Get the contained mapping.
Definition: Transform.h:135
std::shared_ptr< Transform > readStream(std::istream &is)
Deserialize a Transform from an input stream.
T to_string(T... args)
Transform(Transform const &)=default
table::Schema schema
Definition: Transform.cc:197
void writeStream(Transform const &transform, std::ostream &os)
Serialize a Transform to an output stream.
table::Key< int > transform
An abstract base class for objects which transform one set of coordinates to another.
Definition: Mapping.h:59
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:202
STL class.
STL class.
std::shared_ptr< FrameSet > copy() const
Return a deep copy of this object.
Definition: FrameSet.h:145
A base class for image defects.
Definition: cameraGeom.dox:3
FromPoint applyInverse(ToPoint const &point) const
Transform one point in the inverse direction ("to" to "from")
Definition: Transform.cc:94
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
T str(T... args)
T dynamic_pointer_cast(T... args)
Reports errors in the logical structure of the program.
Definition: Runtime.h:46
double x
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:47
Reports invalid arguments.
Definition: Runtime.h:66
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
ndarray::Array< std::uint8_t, 1, 1 > stringToBytes(std::string const &str)
Encode a std::string as a vector of uint8.
Definition: Utils.cc:191
#define INSTANTIATE_TRANSFORM(FromEndpoint, ToEndpoint)
Definition: Transform.cc:255
STL class.
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
std::ostream * os
Definition: Schema.cc:737
Transform LSST spatial data, such as lsst::geom::Point2D and lsst::geom::SpherePoint, using an AST mapping.
Definition: Transform.h:67
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:472