LSSTApplications  11.0-24-g0a022a1,14.0+64,15.0,15.0+1,15.0-1-g14e9bfd,15.0-1-g1eca518,15.0-1-g499c38d,15.0-1-g60afb23,15.0-1-g6668b0b,15.0-1-g788a293,15.0-1-g82223af,15.0-1-ga91101e,15.0-1-gae1598d,15.0-1-gc45031d,15.0-1-gd076f1f,15.0-1-gf4f1c34,15.0-1-gfe1617d,15.0-16-g953e39cab,15.0-2-g2010ef9,15.0-2-g33d94b3,15.0-2-g5218728,15.0-2-g947dc0d,15.0-3-g9103c06,15.0-3-ga03b4ca,15.0-3-ga659d1f3,15.0-3-ga695220+2,15.0-3-gaec6799,15.0-3-gb7a597c,15.0-3-gd5b9ff95,15.0-4-g0478fed+2,15.0-4-g45f767a,15.0-4-gff20472+2,15.0-6-ge2d9597
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"
37 
38 namespace lsst {
39 namespace afw {
40 namespace geom {
41 
42 template <class FromEndpoint, class ToEndpoint>
44  : _fromEndpoint(mapping.getNIn()),
45  _mapping(simplify ? mapping.simplify() : mapping.copy()), _toEndpoint(mapping.getNOut()) {}
46 
47 template <typename FromEndpoint, typename ToEndpoint>
49  : _fromEndpoint(frameSet.getNIn()), _mapping(), _toEndpoint(frameSet.getNOut()) {
50  auto frameSetCopy = frameSet.copy();
51  // Normalize the base and current frame in a way that affects its behavior as a mapping.
52  // To do this one must set the current frame to the frame to be normalized
53  // and normalize the frame set as a frame (i.e. normalize the frame "in situ").
54  // The obvious alternative of normalizing a shallow copy of the frame does not work;
55  // the frame is altered but not the associated mapping!
56 
57  // Normalize the current frame by normalizing the frameset as a frame
58  _toEndpoint.normalizeFrame(frameSetCopy);
59 
60  // Normalize the base frame by temporarily making it the current frame,
61  // normalizing the frameset as a frame, then making it the base frame again
62  const int baseIndex = frameSetCopy->getBase();
63  const int currentIndex = frameSetCopy->getCurrent();
64  frameSetCopy->setCurrent(baseIndex);
65  _fromEndpoint.normalizeFrame(frameSetCopy);
66  frameSetCopy->setBase(baseIndex);
67  frameSetCopy->setCurrent(currentIndex);
68  _mapping = simplify ? frameSetCopy->getMapping()->simplify() : frameSetCopy->getMapping();
69 }
70 
71 template <typename FromEndpoint, typename ToEndpoint>
73  : _fromEndpoint(mapping->getNIn()), _mapping(mapping), _toEndpoint(mapping->getNOut()) {
74 }
75 
76 template <class FromEndpoint, class ToEndpoint>
78  typename FromEndpoint::Point const &point) const {
79  auto const rawFromData = _fromEndpoint.dataFromPoint(point);
80  auto rawToData = _mapping->applyForward(rawFromData);
81  return _toEndpoint.pointFromData(rawToData);
82 }
83 
84 template <class FromEndpoint, class ToEndpoint>
86  typename FromEndpoint::Array const &array) const {
87  auto const rawFromData = _fromEndpoint.dataFromArray(array);
88  auto rawToData = _mapping->applyForward(rawFromData);
89  return _toEndpoint.arrayFromData(rawToData);
90 }
91 
92 template <class FromEndpoint, class ToEndpoint>
94  typename ToEndpoint::Point const &point) const {
95  auto const rawFromData = _toEndpoint.dataFromPoint(point);
96  auto rawToData = _mapping->applyInverse(rawFromData);
97  return _fromEndpoint.pointFromData(rawToData);
98 }
99 
100 template <class FromEndpoint, class ToEndpoint>
102  typename ToEndpoint::Array const &array) const {
103  auto const rawFromData = _toEndpoint.dataFromArray(array);
104  auto rawToData = _mapping->applyInverse(rawFromData);
105  return _fromEndpoint.arrayFromData(rawToData);
106 }
107 
108 template <class FromEndpoint, class ToEndpoint>
110  auto inverse = std::dynamic_pointer_cast<ast::Mapping>(_mapping->getInverse());
111  if (!inverse) {
112  // don't throw std::bad_cast because it doesn't let you provide debugging info
113  std::ostringstream buffer;
114  buffer << "Mapping.getInverse() does not return a Mapping. Called from: " << _mapping;
116  }
117  return std::make_shared<Transform<ToEndpoint, FromEndpoint>>(*inverse);
118 }
119 
120 template <class FromEndpoint, class ToEndpoint>
122  int const nIn = _fromEndpoint.getNAxes();
123  int const nOut = _toEndpoint.getNAxes();
124  std::vector<double> const point = _fromEndpoint.dataFromPoint(x);
125 
126  Eigen::MatrixXd jacobian(nOut, nIn);
127  for (int i = 0; i < nOut; ++i) {
128  for (int j = 0; j < nIn; ++j) {
129  jacobian(i, j) = _mapping->rate(point, i + 1, j + 1);
130  }
131  }
132  return jacobian;
133 }
134 
135 template <class FromEndpoint, class ToEndpoint>
138  os << "Transform" << FromEndpoint::getClassPrefix() << "To" << ToEndpoint::getClassPrefix();
139  return os.str();
140 }
141 
142 template <class FromEndpoint, class ToEndpoint>
144 std::istream &is) {
145  return detail::readStream<Transform<FromEndpoint, ToEndpoint>>(is);
146 }
147 
148 template <class FromEndpoint, class ToEndpoint>
150 std::string &str) {
151  std::istringstream is(str);
153 }
154 
155 template <class FromEndpoint, class ToEndpoint>
157  detail::writeStream<Transform<FromEndpoint, ToEndpoint>>(*this, os);
158 }
159 
160 template <class FromEndpoint, class ToEndpoint>
163  writeStream(os);
164  return os.str();
165 }
166 
167 template <class FromEndpoint, class ToEndpoint>
168 template <class NextToEndpoint>
170 Transform<ToEndpoint, NextToEndpoint> const &next, bool simplify) const {
171  if (_toEndpoint.getNAxes() == next.getFromEndpoint().getNAxes()) {
172  auto nextMapping = next.getMapping();
173  auto combinedMapping = getMapping()->then(*next.getMapping());
174  if (simplify) {
175  return std::make_shared<Transform<FromEndpoint, NextToEndpoint>>(*combinedMapping.simplify());
176  } else {
177  return std::make_shared<Transform<FromEndpoint, NextToEndpoint>>(combinedMapping);
178  }
179  } else {
180  auto message = "Cannot match " + std::to_string(_toEndpoint.getNAxes()) + "-D to-endpoint to " +
181  std::to_string(next.getFromEndpoint().getNAxes()) + "-D from-endpoint.";
183  }
184 }
185 
186 template <class FromEndpoint, class ToEndpoint>
187 std::ostream &operator<<(std::ostream &os, Transform<FromEndpoint, ToEndpoint> const &transform) {
188  os << "Transform<" << transform.getFromEndpoint() << ", " << transform.getToEndpoint() << ">";
189  return os;
190 };
191 
192 namespace {
193 
194 class TransformPersistenceHelper {
195 public:
196  table::Schema schema;
197  table::Key<table::Array<std::uint8_t>> bytes;
198 
199  static TransformPersistenceHelper const & get() {
200  static TransformPersistenceHelper instance;
201  return instance;
202  }
203 
204  // No copying
205  TransformPersistenceHelper(TransformPersistenceHelper const &) = delete;
206  TransformPersistenceHelper& operator=(TransformPersistenceHelper const &) = delete;
207 
208  // No moving
209  TransformPersistenceHelper(TransformPersistenceHelper&&) = delete;
210  TransformPersistenceHelper& operator=(TransformPersistenceHelper&&) = delete;
211 
212 private:
213  TransformPersistenceHelper() :
214  schema(),
215  bytes(
216  schema.addField<table::Array<std::uint8_t>>(
217  "bytes",
218  "a bytestring containing the output of Transform.writeString", ""
219  )
220  )
221  {
222  schema.getCitizen().markPersistent();
223  }
224 
225 };
226 
227 template <typename FromEndpoint, typename ToEndpoint>
228 class TransformFactory : public table::io::PersistableFactory {
229 public:
230  explicit TransformFactory(std::string const & name) : table::io::PersistableFactory(name) {}
231 
232  virtual std::shared_ptr<table::io::Persistable> read(InputArchive const& archive,
233  CatalogVector const& catalogs) const {
234  auto const & keys = TransformPersistenceHelper::get();
235  LSST_ARCHIVE_ASSERT(catalogs.size() == 1u);
236  LSST_ARCHIVE_ASSERT(catalogs.front().size() == 1u);
237  LSST_ARCHIVE_ASSERT(catalogs.front().getSchema() == keys.schema);
238  auto const & record = catalogs.front().front();
239  std::string stringRep = formatters::bytesToString(record.get(keys.bytes));
240  return Transform<FromEndpoint, ToEndpoint>::readString(stringRep);
241  }
242 };
243 
244 } // anonymous
245 
246 
247 
248 template <class FromEndpoint, class ToEndpoint>
250  auto const& keys = TransformPersistenceHelper::get();
251  table::BaseCatalog cat = handle.makeCatalog(keys.schema);
253  record->set(keys.bytes, formatters::stringToBytes(writeString()));
254  handle.saveCatalog(cat);
255 }
256 
257 
258 #define INSTANTIATE_OVERLOADS(FromEndpoint, ToEndpoint, NextToEndpoint) \
259  template std::shared_ptr<Transform<FromEndpoint, NextToEndpoint>> \
260  Transform<FromEndpoint, ToEndpoint>::then<NextToEndpoint>( \
261  Transform<ToEndpoint, NextToEndpoint> const &next, bool) const;
262 
263 #define INSTANTIATE_TRANSFORM(FromEndpoint, ToEndpoint) \
264  template class Transform<FromEndpoint, ToEndpoint>; \
265  template std::ostream &operator<<<FromEndpoint, ToEndpoint>( \
266  std::ostream &os, Transform<FromEndpoint, ToEndpoint> const &transform); \
267  namespace { \
268  TransformFactory<FromEndpoint, ToEndpoint> registration ## FromEndpoint ## ToEndpoint( \
269  Transform<FromEndpoint, ToEndpoint>::getShortClassName() \
270  ); \
271  } \
272  INSTANTIATE_OVERLOADS(FromEndpoint, ToEndpoint, GenericEndpoint) \
273  INSTANTIATE_OVERLOADS(FromEndpoint, ToEndpoint, Point2Endpoint) \
274  INSTANTIATE_OVERLOADS(FromEndpoint, ToEndpoint, SpherePointEndpoint)
275 
276 // explicit instantiations
277 INSTANTIATE_TRANSFORM(GenericEndpoint, GenericEndpoint);
278 INSTANTIATE_TRANSFORM(GenericEndpoint, Point2Endpoint);
279 INSTANTIATE_TRANSFORM(GenericEndpoint, SpherePointEndpoint);
280 INSTANTIATE_TRANSFORM(Point2Endpoint, GenericEndpoint);
281 INSTANTIATE_TRANSFORM(Point2Endpoint, Point2Endpoint);
282 INSTANTIATE_TRANSFORM(Point2Endpoint, SpherePointEndpoint);
283 INSTANTIATE_TRANSFORM(SpherePointEndpoint, GenericEndpoint);
284 INSTANTIATE_TRANSFORM(SpherePointEndpoint, Point2Endpoint);
285 INSTANTIATE_TRANSFORM(SpherePointEndpoint, SpherePointEndpoint);
286 
287 } // namespace geom
288 } // namespace afw
289 } // namespace lsst
FromEndpoint getFromEndpoint() const
Get the "from" endpoint.
Definition: Transform.h:132
ToPoint applyForward(FromPoint const &point) const
Transform one point in the forward direction ("from" to "to")
Definition: Transform.cc:77
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:137
std::shared_ptr< Transform > readStream(std::istream &is)
Deserialize a Transform from an input stream.
T to_string(T... args)
Transform(Transform const &)=default
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:204
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:93
#define INSTANTIATE_TRANSFORM(FromEndpoint, ToEndpoint)
Definition: Transform.cc:263
T str(T... args)
T dynamic_pointer_cast(T... args)
table::Schema schema
Definition: Transform.cc:196
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 and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
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:193
STL class.
table::Key< table::Array< std::uint8_t > > bytes
Definition: Transform.cc:197
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:736
Transform LSST spatial data, such as Point2D and 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