23#include <unordered_set>
39static lsst::afw::geom::Point2Endpoint
const POINT2_ENDPOINT;
41static auto LOGGER =
LOG_GET(
"lsst.afw.cameraGeom.TransformMap");
44std::string makeFrameName(
CameraSys const & sys) {
45 std::string
r =
"Ident=" + sys.getSysName();
46 if (sys.hasDetectorName()) {
48 r += sys.getDetectorName();
77std::vector<TransformMap::Connection> standardizeConnections(
79 std::vector<TransformMap::Connection> connections
81 if (connections.
empty()) {
83 pex::exceptions::InvalidParameterError,
84 "Cannot create a TransformMap with no connections."
89 auto firstUnprocessed = connections.
begin();
92 std::unordered_set<CameraSys> knownSystems = {reference};
97 std::unordered_set<CameraSys> currentSystems = {reference};
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 <<
", ");
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));
115 connection->reverse();
119 if (connection->toSys == connection->fromSys) {
120 std::ostringstream ss;
121 ss <<
"Identity connection found: " << (*connection) <<
".";
122 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.
str());
124 if (knownSystems.
count(connection->toSys)) {
125 std::ostringstream ss;
126 ss <<
"Multiple paths between reference " << reference
127 <<
" and " << connection->toSys <<
".";
128 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.
str());
130 LOGLS_DEBUG(LOGGER,
"Standardizing: adding " << (*connection));
131 nextSystems.
insert(connection->toSys);
132 knownSystems.
insert(connection->toSys);
133 std::swap(*firstUnprocessed, *connection);
137 currentSystems.swap(nextSystems);
142 if (firstUnprocessed != connections.
end()) {
143 std::ostringstream ss;
144 ss <<
"Disconnected connection(s) found: " << (*firstUnprocessed);
146 for (
auto connection = firstUnprocessed; connection != connections.
end(); ++connection) {
147 ss <<
", " << (*connection);
150 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.
str());
158CameraSys getReferenceSys(std::vector<TransformMap::Connection>
const & connections) {
159 return connections.
front().fromSys;
170 return os << connection.
fromSys <<
"->" << connection.
toSys;
179 for (
auto const & pair : transforms) {
194 new TransformMap(standardizeConnections(reference, connections))
204 auto mapping = _getMapping(fromSys, toSys);
211 auto mapping = _getMapping(fromSys, toSys);
222int TransformMap::_getFrame(
CameraSys const &system)
const {
224 return _frameIds.
at(system);
227 buffer <<
"Unsupported coordinate system: " << system;
233 CameraSys
const &toSys)
const {
234 return _frameSet->
getMapping(_getFrame(fromSys), _getFrame(toSys));
241 _connections(
std::move(connections))
246 assert(!_connections.empty());
257 _frameIds.
emplace(sys, ++nFrames);
264 _frameSet = std::make_unique<ast::FrameSet>(addFrameForSys(getReferenceSys(_connections)));
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));
275 assert(_frameSet->
getNFrame() == nFrames);
283struct PersistenceHelper {
285 static PersistenceHelper
const & get() {
286 static PersistenceHelper
const instance;
302 PersistenceHelper() :
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.",
""))
315 PersistenceHelper(PersistenceHelper
const &) =
delete;
316 PersistenceHelper(PersistenceHelper &&) =
delete;
318 PersistenceHelper & operator=(PersistenceHelper
const &) =
delete;
319 PersistenceHelper & operator=(PersistenceHelper &&) =
delete;
326struct OldPersistenceHelper {
328 static OldPersistenceHelper
const & get() {
329 static OldPersistenceHelper
const instance;
336 table::Schema sysSchema;
337 table::Key<std::string> sysName;
338 table::Key<std::string> detectorName;
346 table::Schema connectionSchema;
347 table::Key<int> from;
349 table::Key<int> transform;
351 CameraSys makeCameraSys(table::BaseRecord
const & record)
const {
352 return CameraSys(record.get(sysName), record.get(detectorName));
357 OldPersistenceHelper() :
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.",
""))
369 OldPersistenceHelper(OldPersistenceHelper
const &) =
delete;
370 OldPersistenceHelper(OldPersistenceHelper &&) =
delete;
372 OldPersistenceHelper & operator=(OldPersistenceHelper
const &) =
delete;
373 OldPersistenceHelper & operator=(OldPersistenceHelper &&) =
delete;
382 return "TransformMap";
386 return "lsst.afw.cameraGeom";
390 auto const & keys = PersistenceHelper::get();
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));
411 auto const & keys = OldPersistenceHelper::get();
414 auto const & sysCat = catalogs[0];
415 auto const & connectionCat = catalogs[1];
422 for (
auto const & sysRecord : sysCat) {
423 auto sys = keys.makeCameraSys(sysRecord);
424 sysById.
emplace(sysRecord.get(keys.id), sys);
427 auto const referenceSysIter = sysById.
find(1);
430 for (
auto const & connectionRecord : connectionCat) {
431 auto const fromSysIter = sysById.
find(connectionRecord.get(keys.from));
433 auto const toSysIter = sysById.
find(connectionRecord.get(keys.to));
435 auto const transform = archive.
get<geom::TransformPoint2ToPoint2>(
436 connectionRecord.get(keys.transform)
442 connections = standardizeConnections(referenceSysIter->second,
std::move(connections));
448 if (catalogs.size() == 2u) {
449 return readOld(archive, catalogs);
452 auto const & keys = PersistenceHelper::get();
455 auto const & cat = catalogs[0];
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));
468 auto const referenceSys = getReferenceSys(connections);
469 connections = standardizeConnections(referenceSys,
std::move(connections));
484template class PersistableFacade<cameraGeom::TransformMap>;
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
LSST DM logging module built on log4cxx.
#define LOG_GET(logger)
Returns a Log object associated with logger.
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Frame is used to represent a coordinate system.
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,...
std::shared_ptr< Mapping > getMapping(int from=BASE, int to=CURRENT) const
Obtain a Mapping that converts between two Frames in a FrameSet.
int getNFrame() const
Get FrameSet_NFrame "NFrame": number of Frames in the FrameSet, starting from 1.
Camera coordinate system; used as a key in in TransformMap.
ndarray::Array< double, 2, 2 > dataFromArray(Array const &arr) const override
std::vector< double > dataFromPoint(Point const &point) const override
Point pointFromData(std::vector< double > const &data) const override
Get a single point from raw data.
Array arrayFromData(ndarray::Array< double, 2, 2 > const &data) const override
Get an array of points from raw data.
A class used as a handle to a particular field in a table.
Defines the fields and offsets for a table.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
int put(Persistable const *obj, bool permissive=false)
Save an object to the archive and return a unique ID that can be used to retrieve it from an InputArc...
A base class for factory classes used to reconstruct objects from records.
io::CatalogVector CatalogVector
io::InputArchive InputArchive
PersistableFactory(std::string const &name)
Constructor for the factory.
io::OutputArchiveHandle OutputArchiveHandle
Reports invalid arguments.
transform(self, *, outOffset=None, outFlipX=False, outFlipY=False)
std::ostream & operator<<(std::ostream &os, CameraSysPrefix const &detSysPrefix)
T throw_with_nested(T... args)