LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
LSST Data Management Base Package
TransformMap.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 /*
3  * Developed for the LSST Data Management System.
4  * This product includes software developed by the LSST Project
5  * (https://www.lsst.org).
6  * See the COPYRIGHT file at the top-level directory of this distribution
7  * for details of code ownership.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  */
22 #include <sstream>
23 #include <unordered_set>
24 
25 #include "lsst/log/Log.h"
26 #include "lsst/pex/exceptions.h"
31 
32 namespace lsst {
33 namespace afw {
34 namespace cameraGeom {
35 
36 namespace {
37 
38 // Allows conversions between LSST and AST data formats
39 static lsst::afw::geom::Point2Endpoint const POINT2_ENDPOINT;
40 
41 static auto LOGGER = LOG_GET("afw.cameraGeom.TransformMap");
42 
43 // Make an AST Frame name for a CameraSys.
44 std::string makeFrameName(CameraSys const & sys) {
45  std::string r = "Ident=" + sys.getSysName();
46  if (sys.hasDetectorName()) {
47  r += "_";
48  r += sys.getDetectorName();
49  }
50  return r;
51 }
52 
53 /*
54  * Make a vector of `Connection` instances that can be safely passed to
55  * TransformMap's private constructor.
56  *
57  * This guarantees that:
58  * - Connections are sorted according to their distance (in number of
59  * intermediate connections) from the given reference `CameraSys`;
60  * - The `fromSys` of each `Connection` is closer to the reference than the
61  * `toSys`.
62  *
63  * @param[in] reference Reference coordinate system. All systems must be
64  * (indirectly) connected to this system, and will be
65  * sorted according to the number of connections to it.
66  * @param[in] connections Vector of `Connection` instances. Passed by value so
67  * we can either move into it (avoiding a copy) or copy
68  * into it (when we have a const reference and a copy is
69  * unavoidable), depending on the context.
70  *
71  * @returns connections An updated version of the connections vector.
72  *
73  * @throws pex::exceptions::InvalidParameterError Thrown if the vector of
74  * connections graph is empty, contains cycles, is not fully connected, or
75  * includes any connections in which `fromSys == toSys`.
76  */
77 std::vector<TransformMap::Connection> standardizeConnections(
78  CameraSys const & reference,
80 ) {
81  if (connections.empty()) {
82  throw LSST_EXCEPT(
83  pex::exceptions::InvalidParameterError,
84  "Cannot create a TransformMap with no connections."
85  );
86  }
87  // Iterator to the first unprocessed connection in result; will be
88  // incremented as we proceed.
89  auto firstUnprocessed = connections.begin();
90  // All CameraSys whose associated Connections are already in the processed
91  // part of `connections`.
92  std::unordered_set<CameraSys> knownSystems = {reference};
93  // The set of CameraSys whose associated Connections are being processed
94  // in this iteration of the outer (while) loop. These are all some common
95  // distance N from the reference system (in number of connections), where
96  // N increases for each iteration (but is not tracked).
97  std::unordered_set<CameraSys> currentSystems = {reference};
98  // The set of CameraSys that will become currentSys at the next
99  // iteration.
100  std::unordered_set<CameraSys> nextSystems;
101  LOGLS_DEBUG(LOGGER, "Standardizing: starting with reference " << reference);
102  while (!currentSystems.empty()) {
103  LOGLS_DEBUG(LOGGER, "Standardizing: beginning iteration with currentSystems={ ");
104  for (auto const & sys : currentSystems) {
105  LOGLS_DEBUG(LOGGER, "Standardizing: " << sys << ", ");
106  }
107  LOGLS_DEBUG(LOGGER, "Standardizing: }");
108  // Iterate over all unsorted connections, looking for those associated
109  // with a CameraSys in currentSystems.
110  for (auto connection = firstUnprocessed; connection != connections.end(); ++connection) {
111  bool related = currentSystems.count(connection->fromSys) > 0;
112  if (!related && currentSystems.count(connection->toSys)) {
113  LOGLS_DEBUG(LOGGER, "Standardizing: reversing " << (*connection));
114  // Safe because `connections` is passed by value.
115  connection->reverse();
116  related = true;
117  }
118  if (related) {
119  if (connection->toSys == connection->fromSys) {
121  ss << "Identity connection found: " << (*connection) << ".";
122  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.str());
123  }
124  if (knownSystems.count(connection->toSys)) {
126  ss << "Multiple paths between reference " << reference
127  << " and " << connection->toSys << ".";
128  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.str());
129  }
130  LOGLS_DEBUG(LOGGER, "Standardizing: adding " << (*connection));
131  nextSystems.insert(connection->toSys);
132  knownSystems.insert(connection->toSys);
133  std::swap(*firstUnprocessed, *connection);
134  ++firstUnprocessed;
135  }
136  }
137  currentSystems.swap(nextSystems);
138  nextSystems.clear();
139  }
140  // Any connections we haven't processed yet must include only CameraSys
141  // we've never seen before.
142  if (firstUnprocessed != connections.end()) {
144  ss << "Disconnected connection(s) found: " << (*firstUnprocessed);
145  ++firstUnprocessed;
146  for (auto connection = firstUnprocessed; connection != connections.end(); ++connection) {
147  ss << ", " << (*connection);
148  }
149  ss << ".";
150  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.str());
151  }
152  // No RVO, because this is a function argument, but it's still a move so we
153  // don't care.
154  return connections;
155 }
156 
157 // Return the reference coordinate system from an already-standardized vector of connections.
158 CameraSys getReferenceSys(std::vector<TransformMap::Connection> const & connections) {
159  return connections.front().fromSys;
160 }
161 
162 } // anonymous
163 
165  transform = transform->inverted();
166  toSys.swap(fromSys);
167 }
168 
170  return os << connection.fromSys << "->" << connection.toSys;
171 }
172 
174  CameraSys const & reference,
175  Transforms const & transforms
176 ) {
177  std::vector<Connection> connections;
178  connections.reserve(transforms.size());
179  for (auto const & pair : transforms) {
180  connections.push_back(Connection{pair.second, reference, pair.first});
181  }
182  // We can't use make_shared because TransformMap ctor is private.
184  new TransformMap(standardizeConnections(reference, std::move(connections)))
185  );
186 }
187 
189  CameraSys const &reference,
190  std::vector<Connection> const & connections
191 ) {
192  // We can't use make_shared because TransformMap ctor is private.
194  new TransformMap(standardizeConnections(reference, connections))
195  );
196 }
197 
198 
199 // All resources owned by value or by smart pointer
200 TransformMap::~TransformMap() noexcept = default;
201 
202 lsst::geom::Point2D TransformMap::transform(lsst::geom::Point2D const &point, CameraSys const &fromSys,
203  CameraSys const &toSys) const {
204  auto mapping = _getMapping(fromSys, toSys);
205  return POINT2_ENDPOINT.pointFromData(mapping->applyForward(POINT2_ENDPOINT.dataFromPoint(point)));
206 }
207 
209  CameraSys const &fromSys,
210  CameraSys const &toSys) const {
211  auto mapping = _getMapping(fromSys, toSys);
212  return POINT2_ENDPOINT.arrayFromData(mapping->applyForward(POINT2_ENDPOINT.dataFromArray(pointList)));
213 }
214 
215 bool TransformMap::contains(CameraSys const &system) const noexcept { return _frameIds.count(system) > 0; }
216 
218  CameraSys const &toSys) const {
219  return std::make_shared<geom::TransformPoint2ToPoint2>(*_getMapping(fromSys, toSys));
220 }
221 
222 int TransformMap::_getFrame(CameraSys const &system) const {
223  try {
224  return _frameIds.at(system);
225  } catch (std::out_of_range const &e) {
226  std::ostringstream buffer;
227  buffer << "Unsupported coordinate system: " << system;
229  }
230 }
231 
232 std::shared_ptr<ast::Mapping const> TransformMap::_getMapping(CameraSys const &fromSys,
233  CameraSys const &toSys) const {
234  return _frameSet->getMapping(_getFrame(fromSys), _getFrame(toSys));
235 }
236 
237 size_t TransformMap::size() const noexcept { return _frameIds.size(); }
238 
239 
241  _connections(std::move(connections))
242 {
243  // standardizeConnections must be run by anything that calls the
244  // constructor, and that should throw on all of the conditions we assert
245  // on below (which is why those are asserts).
246  assert(!_connections.empty());
247 
248  int nFrames = 0; // tracks frameSet->getNFrame() to avoid those (expensive) calls
249 
250  // Local helper function that creates a Frame, updates the nFrames counter,
251  // and adds an entry to the frameIds map. Returns the new Frame.
252  // Should always be called in concert with an update to frameSet.
253  auto addFrameForSys = [this, &nFrames](CameraSys const & sys) mutable -> ast::Frame {
254  #ifndef NDEBUG
255  auto r = // We only care about this return value for the assert below;
256  #endif
257  _frameIds.emplace(sys, ++nFrames);
258  assert(r.second); // this must actually insert something, not find an already-inserted CameraSys.
259  return ast::Frame(2, makeFrameName(sys));
260  };
261 
262  // FrameSet that manages all transforms; should always be updated in
263  // concert with a call to addFrameForSys.
264  _frameSet = std::make_unique<ast::FrameSet>(addFrameForSys(getReferenceSys(_connections)));
265 
266  for (auto const & connection : _connections) {
267  auto fromSysIdIter = _frameIds.find(connection.fromSys);
268  assert(fromSysIdIter != _frameIds.end());
269  _frameSet->addFrame(fromSysIdIter->second, *connection.transform->getMapping(),
270  addFrameForSys(connection.toSys));
271  }
272 
273  // We've maintained our own counter for frame IDs for performance and
274  // convenience reasons, but it had better match AST's internal counter.
275  assert(_frameSet->getNFrame() == nFrames);
276 }
277 
279 
280 
281 namespace {
282 
283 struct PersistenceHelper {
284 
285  static PersistenceHelper const & get() {
286  static PersistenceHelper const instance;
287  return instance;
288  }
289 
290  // Schema and keys for the catalog that stores Connection objects.
291  // Considered as a graph, 'from' and 'to' identify vertices, and
292  // 'transform' identifies an edge.
293  table::Schema schema;
294  table::Key<std::string> fromSysName;
295  table::Key<std::string> fromSysDetectorName;
296  table::Key<std::string> toSysName;
297  table::Key<std::string> toSysDetectorName;
298  table::Key<int> transform;
299 
300 private:
301 
302  PersistenceHelper() :
303  schema(),
304  fromSysName(schema.addField<std::string>("fromSysName",
305  "Camera coordinate system name.", "", 0)),
306  fromSysDetectorName(schema.addField<std::string>("fromSysDetectorName",
307  "Camera coordinate system detector name.", "", 0)),
308  toSysName(schema.addField<std::string>("toSysName",
309  "Camera coordinate system name.", "", 0)),
310  toSysDetectorName(schema.addField<std::string>("toSysDetectorName",
311  "Camera coordinate system detector name.", "", 0)),
312  transform(schema.addField<int>("transform", "Archive ID of the transform.", ""))
313  {}
314 
315  PersistenceHelper(PersistenceHelper const &) = delete;
316  PersistenceHelper(PersistenceHelper &&) = delete;
317 
318  PersistenceHelper & operator=(PersistenceHelper const &) = delete;
319  PersistenceHelper & operator=(PersistenceHelper &&) = delete;
320 
321 };
322 
323 
324 // PersistenceHelper for a previous format version; now only supported in
325 // reading.
326 struct OldPersistenceHelper {
327 
328  static OldPersistenceHelper const & get() {
329  static OldPersistenceHelper const instance;
330  return instance;
331  }
332 
333  // Schema and keys for the catalog that stores TransformMap._frameIds.
334  // Considered as a graph, this is a list of all of the vertices with the
335  // integers that identify them in the list of edges below.
336  table::Schema sysSchema;
337  table::Key<std::string> sysName;
338  table::Key<std::string> detectorName;
339  table::Key<int> id;
340 
341  // Schema and keys for the catalog that stores
342  // TransformMap._canonicalConnections entries and the associated Transform
343  // extracted from TransformMap._transforms.
344  // Considered as a graph, 'from' and 'to' identify vertices, and
345  // 'transform' identifies an edge.
346  table::Schema connectionSchema;
347  table::Key<int> from;
348  table::Key<int> to;
349  table::Key<int> transform;
350 
351  CameraSys makeCameraSys(table::BaseRecord const & record) const {
352  return CameraSys(record.get(sysName), record.get(detectorName));
353  }
354 
355 private:
356 
357  OldPersistenceHelper() :
358  sysSchema(),
359  sysName(sysSchema.addField<std::string>("sysName", "Camera coordinate system name", "", 0)),
360  detectorName(sysSchema.addField<std::string>("detectorName",
361  "Camera coordinate system detector name", "", 0)),
362  id(sysSchema.addField<int>("id", "AST ID of the Frame for the CameraSys", "")),
364  from(connectionSchema.addField<int>("from", "AST ID of the Frame this transform maps from.", "")),
365  to(connectionSchema.addField<int>("to", "AST ID of the Frame this transform maps to.", "")),
366  transform(connectionSchema.addField<int>("transform", "Archive ID of the transform.", ""))
367  {}
368 
369  OldPersistenceHelper(OldPersistenceHelper const &) = delete;
370  OldPersistenceHelper(OldPersistenceHelper &&) = delete;
371 
372  OldPersistenceHelper & operator=(OldPersistenceHelper const &) = delete;
373  OldPersistenceHelper & operator=(OldPersistenceHelper &&) = delete;
374 
375 };
376 
377 
378 } // namespace
379 
380 
381 std::string TransformMap::getPersistenceName() const {
382  return "TransformMap";
383 }
384 
385 std::string TransformMap::getPythonModule() const {
386  return "lsst.afw.cameraGeom";
387 }
388 
389 void TransformMap::write(OutputArchiveHandle& handle) const {
390  auto const & keys = PersistenceHelper::get();
391 
392  auto cat = handle.makeCatalog(keys.schema);
393  for (auto const & connection : _connections) {
394  auto record = cat.addNew();
395  record->set(keys.fromSysName, connection.fromSys.getSysName());
396  record->set(keys.fromSysDetectorName, connection.fromSys.getDetectorName());
397  record->set(keys.toSysName, connection.toSys.getSysName());
398  record->set(keys.toSysDetectorName, connection.toSys.getDetectorName());
399  record->set(keys.transform, handle.put(connection.transform));
400  }
401  handle.saveCatalog(cat);
402 }
403 
405 public:
406 
407  Factory() : PersistableFactory("TransformMap") {}
408 
410  CatalogVector const& catalogs) const {
411  auto const & keys = OldPersistenceHelper::get();
412 
413  LSST_ARCHIVE_ASSERT(catalogs.size() == 2u);
414  auto const & sysCat = catalogs[0];
415  auto const & connectionCat = catalogs[1];
416  LSST_ARCHIVE_ASSERT(sysCat.getSchema() == keys.sysSchema);
417  LSST_ARCHIVE_ASSERT(connectionCat.getSchema() == keys.connectionSchema);
418  LSST_ARCHIVE_ASSERT(sysCat.size() == connectionCat.size() + 1);
419  LSST_ARCHIVE_ASSERT(sysCat.isSorted(keys.id));
420 
422  for (auto const & sysRecord : sysCat) {
423  auto sys = keys.makeCameraSys(sysRecord);
424  sysById.emplace(sysRecord.get(keys.id), sys);
425  }
426 
427  auto const referenceSysIter = sysById.find(1);
428  LSST_ARCHIVE_ASSERT(referenceSysIter != sysById.end());
429  std::vector<Connection> connections;
430  for (auto const & connectionRecord : connectionCat) {
431  auto const fromSysIter = sysById.find(connectionRecord.get(keys.from));
432  LSST_ARCHIVE_ASSERT(fromSysIter != sysById.end());
433  auto const toSysIter = sysById.find(connectionRecord.get(keys.to));
434  LSST_ARCHIVE_ASSERT(toSysIter != sysById.end());
435  auto const transform = archive.get<geom::TransformPoint2ToPoint2>(
436  connectionRecord.get(keys.transform)
437  );
438 
439  connections.push_back(Connection{transform, fromSysIter->second, toSysIter->second});
440  }
441 
442  connections = standardizeConnections(referenceSysIter->second, std::move(connections));
443  return std::shared_ptr<TransformMap>(new TransformMap(std::move(connections)));
444  }
445 
447  CatalogVector const& catalogs) const override {
448  if (catalogs.size() == 2u) {
449  return readOld(archive, catalogs);
450  }
451 
452  auto const & keys = PersistenceHelper::get();
453 
454  LSST_ARCHIVE_ASSERT(catalogs.size() == 1u);
455  auto const & cat = catalogs[0];
456  LSST_ARCHIVE_ASSERT(cat.getSchema() == keys.schema);
457 
458  std::vector<Connection> connections;
459  for (auto const & record : cat) {
460  CameraSys const fromSys(record.get(keys.fromSysName), record.get(keys.fromSysDetectorName));
461  CameraSys const toSys(record.get(keys.toSysName), record.get(keys.toSysDetectorName));
462  auto const transform = archive.get<geom::TransformPoint2ToPoint2>(record.get(keys.transform));
463  connections.push_back(Connection{transform, fromSys, toSys});
464  }
465 
466  // Deserialized connections should already be standardized, but be
467  // defensive anyway.
468  auto const referenceSys = getReferenceSys(connections);
469  connections = standardizeConnections(referenceSys, std::move(connections));
470  return std::shared_ptr<TransformMap>(new TransformMap(std::move(connections)));
471  }
472 
473  static Factory const registration;
474 
475 };
476 
478 
479 } // namespace cameraGeom
480 
481 namespace table {
482 namespace io {
483 
484 template class PersistableFacade<cameraGeom::TransformMap>;
485 
486 } // namespace io
487 } // namespace table
488 
489 } // namespace afw
490 } // namespace lsst
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
LSST DM logging module built on log4cxx.
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
Definition: Log.h:619
std::ostream * os
Definition: Schema.cc:557
table::Key< int > id
table::Key< std::string > sysName
table::Key< std::string > fromSysName
table::Key< int > from
table::Schema sysSchema
table::Schema schema
table::Key< std::string > toSysDetectorName
table::Key< std::string > fromSysDetectorName
table::Key< int > to
table::Key< int > transform
table::Key< std::string > toSysName
table::Key< std::string > detectorName
table::Schema connectionSchema
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
T at(T... args)
T begin(T... args)
Frame is used to represent a coordinate system.
Definition: Frame.h:157
virtual void addFrame(int iframe, Mapping const &map, Frame const &frame)
Add a new Frame and an associated Mapping to this FrameSet so as to define a new coordinate system,...
Definition: FrameSet.h:210
std::shared_ptr< Mapping > getMapping(int from=BASE, int to=CURRENT) const
Obtain a Mapping that converts between two Frames in a FrameSet.
Definition: FrameSet.h:304
int getNFrame() const
Get FrameSet_NFrame "NFrame": number of Frames in the FrameSet, starting from 1.
Definition: FrameSet.h:316
Camera coordinate system; used as a key in in TransformMap.
Definition: CameraSys.h:83
void swap(CameraSys &other) noexcept
Definition: CameraSys.h:107
std::shared_ptr< Persistable > readOld(InputArchive const &archive, CatalogVector const &catalogs) const
std::shared_ptr< Persistable > read(InputArchive const &archive, CatalogVector const &catalogs) const override
Construct a new object from the given InputArchive and vector of catalogs.
A registry of 2-dimensional coordinate transforms for a specific camera.
Definition: TransformMap.h:62
static std::shared_ptr< TransformMap const > make(CameraSys const &reference, Transforms const &transforms)
Construct a TransformMap with all transforms relative to a single reference CameraSys.
TransformMap(TransformMap const &other)=delete
size_t size() const noexcept
Get the number of supported coordinate systems.
bool contains(CameraSys const &system) const noexcept
Can this transform to and from the specified coordinate system?
std::vector< Connection > getConnections() const
Return the sequence of connections used to construct this Transform.
std::shared_ptr< geom::TransformPoint2ToPoint2 > getTransform(CameraSys const &fromSys, CameraSys const &toSys) const
Get a Transform from one camera coordinate system to another.
lsst::geom::Point2D transform(lsst::geom::Point2D const &point, CameraSys const &fromSys, CameraSys const &toSys) const
Convert a point from one camera coordinate system to another.
An endpoint for lsst::geom::Point2D.
Definition: Endpoint.h:261
ndarray::Array< double, 2, 2 > dataFromArray(Array const &arr) const override
Get raw data from an array of points.
Definition: Endpoint.cc:123
std::vector< double > dataFromPoint(Point const &point) const override
Get raw data from a single point.
Definition: Endpoint.cc:114
Point pointFromData(std::vector< double > const &data) const override
Get a single point from raw data.
Definition: Endpoint.cc:137
Array arrayFromData(ndarray::Array< double, 2, 2 > const &data) const override
Get an array of points from raw data.
Definition: Endpoint.cc:147
A vector of catalogs used by Persistable.
Definition: CatalogVector.h:29
A multi-catalog archive object used to load table::io::Persistable objects.
Definition: InputArchive.h:31
std::shared_ptr< Persistable > get(int id) const
Load the Persistable with the given ID and return it.
A base class for factory classes used to reconstruct objects from records.
Definition: Persistable.h:228
PersistableFactory(std::string const &name)
Constructor for the factory.
Definition: Persistable.cc:74
Reports invalid arguments.
Definition: Runtime.h:66
T clear(T... args)
T count(T... args)
T emplace(T... args)
T empty(T... args)
T end(T... args)
T find(T... args)
T front(T... args)
T insert(T... args)
T move(T... args)
std::ostream & operator<<(std::ostream &os, CameraSysPrefix const &detSysPrefix)
Definition: CameraSys.cc:47
Transform< Point2Endpoint, Point2Endpoint > TransformPoint2ToPoint2
Definition: Transform.h:300
FilterProperty & operator=(FilterProperty const &)=default
Point< double, 2 > Point2D
Definition: Point.h:324
A base class for image defects.
STL namespace.
T push_back(T... args)
T reserve(T... args)
T size(T... args)
T str(T... args)
Representation of a single edge in the graph defined by a TransformMap.
Definition: TransformMap.h:80
void reverse()
Reverse the connection, by swapping fromSys and toSys and inverting the transform.
std::shared_ptr< geom::TransformPoint2ToPoint2 const > transform
Definition: TransformMap.h:81
T swap(T... args)
T throw_with_nested(T... args)