23#include <unordered_set>
43static lsst::afw::geom::Point2Endpoint
const POINT2_ENDPOINT;
45static auto LOGGER =
LOG_GET(
"lsst.afw.cameraGeom.TransformMap");
48std::string makeFrameName(
CameraSys const &sys) {
49 std::string
r =
"Ident=" + sys.getSysName();
50 if (sys.hasDetectorName()) {
52 r += sys.getDetectorName();
81std::vector<TransformMap::Connection> standardizeConnections(
82 CameraSys const &reference, std::vector<TransformMap::Connection> connections) {
83 if (connections.
empty()) {
84 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
85 "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 <<
" 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;
177 for (
auto const &pair : transforms) {
189 new TransformMap(standardizeConnections(reference, connections)));
197 auto mapping = _getMapping(fromSys, toSys);
204 auto mapping = _getMapping(fromSys, toSys);
217int TransformMap::_getFrame(
CameraSys const &system)
const {
219 return _frameIds.
at(system);
222 buffer <<
"Unsupported coordinate system: " << system;
228 CameraSys
const &toSys)
const {
229 return _frameSet->
getMapping(_getFrame(fromSys), _getFrame(toSys));
235 : _connections(
std::move(connections)), _focalPlaneParity(false) {
239 assert(!_connections.empty());
250 _frameIds.
emplace(sys, ++nFrames);
257 _frameSet = std::make_unique<ast::FrameSet>(addFrameForSys(getReferenceSys(_connections)));
259 for (
auto const &connection : _connections) {
260 auto fromSysIdIter = _frameIds.
find(connection.fromSys);
261 assert(fromSysIdIter != _frameIds.
end());
262 _frameSet->
addFrame(fromSysIdIter->second, *connection.transform->getMapping(),
263 addFrameForSys(connection.toSys));
268 assert(_frameSet->
getNFrame() == nFrames);
275 _focalPlaneParity = (jacobian.determinant() < 0);
276 }
catch (pex::exceptions::InvalidParameterError &) {
284struct PersistenceHelper {
285 static PersistenceHelper
const &get() {
286 static PersistenceHelper
const instance;
304 schema.addField<
std::string>(
"fromSysName",
"Camera coordinate system name.",
"", 0)),
305 fromSysDetectorName(schema.addField<
std::string>(
306 "fromSysDetectorName",
"Camera coordinate system detector name.",
"", 0)),
307 toSysName(schema.addField<
std::string>(
"toSysName",
"Camera coordinate system name.",
"", 0)),
308 toSysDetectorName(schema.addField<
std::string>(
309 "toSysDetectorName",
"Camera coordinate system detector name.",
"", 0)),
310 transform(schema.addField<int>(
"transform",
"Archive ID of the transform.",
"")) {}
312 PersistenceHelper(PersistenceHelper
const &) =
delete;
313 PersistenceHelper(PersistenceHelper &&) =
delete;
315 PersistenceHelper &operator=(PersistenceHelper
const &) =
delete;
316 PersistenceHelper &operator=(PersistenceHelper &&) =
delete;
321struct OldPersistenceHelper {
322 static OldPersistenceHelper
const &get() {
323 static OldPersistenceHelper
const instance;
330 table::Schema sysSchema;
331 table::Key<std::string> sysName;
332 table::Key<std::string> detectorName;
340 table::Schema connectionSchema;
341 table::Key<int> from;
343 table::Key<int> transform;
345 CameraSys makeCameraSys(table::BaseRecord
const &record)
const {
346 return CameraSys(record.get(sysName), record.get(detectorName));
350 OldPersistenceHelper()
352 sysName(sysSchema.addField<std::string>(
"sysName",
"Camera coordinate system name",
"", 0)),
353 detectorName(sysSchema.addField<std::string>(
"detectorName",
354 "Camera coordinate system detector name",
"", 0)),
355 id(sysSchema.addField<
int>(
"id",
"AST ID of the Frame for the CameraSys",
"")),
357 from(connectionSchema.addField<
int>(
"from",
"AST ID of the Frame this transform maps from.",
359 to(connectionSchema.addField<
int>(
"to",
"AST ID of the Frame this transform maps to.",
"")),
360 transform(connectionSchema.addField<
int>(
"transform",
"Archive ID of the transform.",
"")) {}
362 OldPersistenceHelper(OldPersistenceHelper
const &) =
delete;
363 OldPersistenceHelper(OldPersistenceHelper &&) =
delete;
365 OldPersistenceHelper &operator=(OldPersistenceHelper
const &) =
delete;
366 OldPersistenceHelper &operator=(OldPersistenceHelper &&) =
delete;
376 auto const &keys = PersistenceHelper::get();
379 for (
auto const &connection : _connections) {
380 auto record = cat.addNew();
381 record->set(keys.fromSysName, connection.fromSys.getSysName());
382 record->set(keys.fromSysDetectorName, connection.fromSys.getDetectorName());
383 record->set(keys.toSysName, connection.toSys.getSysName());
384 record->set(keys.toSysDetectorName, connection.toSys.getDetectorName());
385 record->set(keys.transform, handle.
put(connection.transform));
395 auto const &keys = OldPersistenceHelper::get();
398 auto const &sysCat = catalogs[0];
399 auto const &connectionCat = catalogs[1];
406 for (
auto const &sysRecord : sysCat) {
407 auto sys = keys.makeCameraSys(sysRecord);
408 sysById.
emplace(sysRecord.get(keys.id), sys);
411 auto const referenceSysIter = sysById.
find(1);
414 for (
auto const &connectionRecord : connectionCat) {
415 auto const fromSysIter = sysById.
find(connectionRecord.get(keys.from));
417 auto const toSysIter = sysById.
find(connectionRecord.get(keys.to));
420 archive.
get<geom::TransformPoint2ToPoint2>(connectionRecord.get(keys.transform));
425 connections = standardizeConnections(referenceSysIter->second,
std::move(connections));
431 if (catalogs.size() == 2u) {
432 return readOld(archive, catalogs);
435 auto const &keys = PersistenceHelper::get();
438 auto const &cat = catalogs[0];
442 for (
auto const &record : cat) {
443 CameraSys const fromSys(record.get(keys.fromSysName), record.get(keys.fromSysDetectorName));
444 CameraSys const toSys(record.get(keys.toSysName), record.get(keys.toSysDetectorName));
445 auto const transform = archive.
get<geom::TransformPoint2ToPoint2>(record.get(keys.transform));
451 auto const referenceSys = getReferenceSys(connections);
452 connections = standardizeConnections(referenceSys,
std::move(connections));
466template 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)
CameraSys const FIELD_ANGLE
Field angle coordinates: Angle of a principal ray relative to the optical axis (x,...
CameraSys const FOCAL_PLANE
Focal plane coordinates: Position on a 2-d planar approximation to the focal plane (x,...
std::ostream & operator<<(std::ostream &os, CameraSysPrefix const &detSysPrefix)
Point< double, 2 > Point2D
T throw_with_nested(T... args)