LSSTApplications  18.1.0
LSSTDataManagementBasePackage
Classes | Public Member Functions | List of all members
lsst::afw::cameraGeom::TransformMap::Builder Class Reference

Helper class used to incrementally construct TransformMap instances. More...

#include <TransformMap.h>

Public Member Functions

 Builder (CameraSys const &reference)
 Construct an empty builder with no transforms and only the given coordinate system. More...
 
 ~Builder () noexcept
 
Builderconnect (CameraSys const &fromSys, CameraSys const &toSys, std::shared_ptr< geom::TransformPoint2ToPoint2 const > transform)
 Add a new coordinate system to the builder. More...
 
Builderconnect (CameraSys const &fromSys, Transforms const &transforms)
 Add multiple connections relative to a single reference CameraSys. More...
 
Builderconnect (Transforms const &transforms)
 Add multiple connections relative to a single reference CameraSys. More...
 
std::shared_ptr< TransformMap const > build () const
 Construct a TransformMap from the connections in the builder. More...
 
 Builder (Builder const &)
 
 Builder (Builder &&)
 
Builderoperator= (Builder const &)
 
Builderoperator= (Builder &&)
 

Detailed Description

Helper class used to incrementally construct TransformMap instances.

Definition at line 239 of file TransformMap.h.

Constructor & Destructor Documentation

◆ Builder() [1/3]

lsst::afw::cameraGeom::TransformMap::Builder::Builder ( CameraSys const &  reference)
explicit

Construct an empty builder with no transforms and only the given coordinate system.

Definition at line 252 of file TransformMap.cc.

252 : _reference(reference) {}

◆ Builder() [2/3]

lsst::afw::cameraGeom::TransformMap::Builder::Builder ( Builder const &  )
default

Builders are copyable, movable, and assignable.

◆ Builder() [3/3]

lsst::afw::cameraGeom::TransformMap::Builder::Builder ( Builder &&  )
default

Builders are copyable, movable, and assignable.

◆ ~Builder()

lsst::afw::cameraGeom::TransformMap::Builder::~Builder ( )
defaultnoexcept

Member Function Documentation

◆ build()

std::shared_ptr< TransformMap const > lsst::afw::cameraGeom::TransformMap::Builder::build ( ) const

Construct a TransformMap from the connections in the builder.

Exceptions
pex::exceptions::InvalidParameterErrorThrown if there is no direct or indirect connection between FOCAL_PLANE and one or more coordinate systems, or there are duplicate connections between any two systems.
Exception Safety
strong

Definition at line 330 of file TransformMap.cc.

330  {
331 
332  int nFrames = 0; // tracks frameSet->getNFrame() to avoid those (expensive) calls
333  CameraSysFrameIdMap frameIds; // mapping from CameraSys to Frame ID (int)
334  std::vector<std::pair<int, int>> canonicalConnections; // remembers the frame IDs we've connected
335 
336  // Local helper function that looks up the Frame ID for a CameraSys, with
337  // results returned via boost::optional.
338  auto findFrameIdForSys = [&frameIds](CameraSys const & sys) -> boost::optional<int> {
339  auto iter = frameIds.find(sys);
340  if (iter != frameIds.end()) {
341  return boost::optional<int>(iter->second);
342  } else {
343  return boost::none;
344  }
345  };
346 
347  // Local helper function that creates a Frame, updates the nFrames counter,
348  // and adds an entry to the frameIds map. Returns the new Frame.
349  // Should always be called in concert with an update to frameSet.
350  auto addFrameForSys = [&frameIds, &nFrames](CameraSys const & sys) mutable -> ast::Frame {
351  frameIds.emplace(sys, ++nFrames);
352  return ast::Frame(2, makeFrameName(sys));
353  };
354 
355  // FrameSet that manages all transforms; should always be updated in
356  // concert with a call to addFrameForSys.
357  auto frameSet = std::make_unique<ast::FrameSet>(addFrameForSys(_reference));
358 
359  // RAII: make sure all 'processed' fields are reset, no matter how we exit
360  auto guard = onScopeExit(
361  [this]() noexcept {
362  for (auto const & c : _connections) { c.processed = false; }
363  }
364  );
365 
366  std::size_t nProcessedTotal = 0;
367  while (nProcessedTotal != _connections.size()) {
368 
369  // Loop over all connections, only inserting those that are connected
370  // to already-inserted connections.
371  std::size_t nProcessedThisPass = 0;
372  for (auto const & c : _connections) {
373  if (c.processed) continue;
374  auto fromId = findFrameIdForSys(c.fromSys);
375  auto toId = findFrameIdForSys(c.toSys);
376  if (fromId && toId) { // We've already inserted both fromSys and toSys. That's a problem.
377  std::ostringstream buffer;
378  buffer << "Duplicate connection from " << c.fromSys << " to " << c.toSys << ".";
379  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, buffer.str());
380  } else if (fromId) { // We've already inserted fromSys (only)
381  frameSet->addFrame(*fromId, *c.transform->getMapping(), addFrameForSys(c.toSys));
382  canonicalConnections.emplace_back(*fromId, nFrames);
383  c.processed = true;
384  ++nProcessedThisPass;
385  } else if (toId) { // We've already inserted toSys (only)
386  frameSet->addFrame(*toId, *c.transform->inverted()->getMapping(), addFrameForSys(c.fromSys));
387  canonicalConnections.emplace_back(*toId, nFrames);
388  c.processed = true;
389  ++nProcessedThisPass;
390  }
391  // If we haven't inserted either yet, just continue; hopefully
392  // we'll have inserted one in a future pass.
393  }
394 
395  if (nProcessedThisPass == 0u) { // We're not making progress, so we must have orphans
396  // Use std::set to compile the list of orphaned coordinate systems
397  // for a friendlier (unique, predictably-ordered) error message.
398  std::set<CameraSys> orphaned;
399  for (auto const & c : _connections) {
400  if (!c.processed) {
401  orphaned.insert(c.fromSys);
402  orphaned.insert(c.toSys);
403  }
404  }
405  std::ostringstream buffer;
406  auto o = orphaned.begin();
407  buffer << "Orphaned coordinate system(s) found: " << *o;
408  for (++o; o != orphaned.end(); ++o) {
409  buffer << ", " << *o;
410  }
411  buffer << ".";
412  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, buffer.str());
413  }
414 
415  nProcessedTotal += nProcessedThisPass;
416  }
417 
418  // We've maintained our own counter for frame IDs for performance and
419  // convenience reasons, but it had better match AST's internal counter.
420  assert(frameSet->getNFrame() == nFrames);
421 
422  // Return the new TransformMap.
423  // We can't use make_shared because TransformMap ctor is private.
425  std::move(frameIds),
426  std::move(canonicalConnections)));
427 }
T end(T... args)
Frame is used to represent a coordinate system.
Definition: Frame.h:157
T str(T... args)
T move(T... args)
T insert(T... args)
T size(T... args)
TransformMap(TransformMap const &other)=delete
STL class.
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
STL class.
T begin(T... args)
T emplace_back(T... args)

◆ connect() [1/3]

TransformMap::Builder & lsst::afw::cameraGeom::TransformMap::Builder::connect ( CameraSys const &  fromSys,
CameraSys const &  toSys,
std::shared_ptr< geom::TransformPoint2ToPoint2 const >  transform 
)

Add a new coordinate system to the builder.

Parameters
fromSysCoordinate system for the arguments to transform->applyForward.
toSysCoordinate system for the return values of transform->applyForward.
transformMapping from fromSys to toSys.
Returns
*this to enable chained calls.
Exceptions
pex::exceptions::InvalidParameterErrorThrown if the transform does not have forward or inverse mapping, or if fromSys and toSys are the same.
Exception Safety
strong

Definition at line 262 of file TransformMap.cc.

266  {
267  if (fromSys == toSys) {
268  std::ostringstream buffer;
269  buffer << "Identity connection detected for " << fromSys << ".";
270  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, buffer.str());
271  }
272  if (!transform->hasForward()) {
273  std::ostringstream buffer;
274  buffer << "Connection from " << fromSys << " to "
275  << toSys << " has no forward transform.";
276  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, buffer.str());
277  }
278  if (!transform->hasInverse()) {
279  std::ostringstream buffer;
280  buffer << "Connection from " << fromSys << " to "
281  << toSys << " has no inverse transform.";
282  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, buffer.str());
283  }
284  _connections.push_back(Connection{false, std::move(transform), fromSys, toSys});
285  return *this;
286 }
T push_back(T... args)
T str(T... args)
T move(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48

◆ connect() [2/3]

TransformMap::Builder & lsst::afw::cameraGeom::TransformMap::Builder::connect ( CameraSys const &  fromSys,
Transforms const &  transforms 
)

Add multiple connections relative to a single reference CameraSys.

Parameters
fromSysCoordinate system of the arguments to Transform::applyForward for each transform in the given map.
transformsA map whose keys are camera coordinate systems, and whose values point to Transforms that convert from fromSys coordinate system to the corresponding key. All Transforms must be invertible.
Returns
*this to enable chained calls.
Exceptions
lsst::pex::exceptions::InvalidParameterErrorThrown if transforms contains fromSys camera system as a key, or if any Transform is not invertible.
Exception Safety
strong

Definition at line 289 of file TransformMap.cc.

292  {
293  Builder other(_reference); // temporary for strong exception safety
294  for (auto const & item : transforms) {
295  other.connect(fromSys, item.first, item.second);
296  }
297  _connections.insert(_connections.end(), other._connections.begin(), other._connections.end());
298  return *this;
299 }
T end(T... args)
Builder(CameraSys const &reference)
Construct an empty builder with no transforms and only the given coordinate system.
T insert(T... args)
ItemVariant const * other
Definition: Schema.cc:56

◆ connect() [3/3]

Builder& lsst::afw::cameraGeom::TransformMap::Builder::connect ( Transforms const &  transforms)
inline

Add multiple connections relative to a single reference CameraSys.

Parameters
transformsA map whose keys are camera coordinate systems, and whose values point to Transforms that convert from the reference coordinate system (i.e. the one the Builder was originally constructed with) to the corresponding key. All Transforms must be invertible.
Returns
*this to enable chained calls.
Exceptions
lsst::pex::exceptions::InvalidParameterErrorThrown if transforms contains the reference camera system as a key, or if any Transform is not invertible.
Exception Safety
strong

Definition at line 317 of file TransformMap.h.

317  {
318  return connect(_reference, transforms);
319  }
Builder & connect(CameraSys const &fromSys, CameraSys const &toSys, std::shared_ptr< geom::TransformPoint2ToPoint2 const > transform)
Add a new coordinate system to the builder.

◆ operator=() [1/2]

TransformMap::Builder & lsst::afw::cameraGeom::TransformMap::Builder::operator= ( Builder const &  )
default

Builders are copyable, movable, and assignable.

◆ operator=() [2/2]

TransformMap::Builder & lsst::afw::cameraGeom::TransformMap::Builder::operator= ( Builder &&  )
default

Builders are copyable, movable, and assignable.


The documentation for this class was generated from the following files: