23#include <unordered_set>
44static lsst::afw::geom::Point2Endpoint
const POINT2_ENDPOINT;
46static auto LOGGER =
LOG_GET(
"lsst.afw.cameraGeom.TransformMap");
49std::string makeFrameName(
CameraSys const &sys) {
50 std::string
r =
"Ident=" + sys.getSysName();
51 if (sys.hasDetectorName()) {
53 r += sys.getDetectorName();
82std::vector<TransformMap::Connection> standardizeConnections(
83 CameraSys const &reference, std::vector<TransformMap::Connection> connections) {
84 if (connections.
empty()) {
85 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
86 "Cannot create a TransformMap with no connections.");
90 auto firstUnprocessed = connections.
begin();
93 std::unordered_set<CameraSys> knownSystems = {reference};
98 std::unordered_set<CameraSys> currentSystems = {reference};
101 std::unordered_set<CameraSys> nextSystems;
102 LOGLS_DEBUG(LOGGER,
"Standardizing: starting with reference " << reference);
103 while (!currentSystems.
empty()) {
104 LOGLS_DEBUG(LOGGER,
"Standardizing: beginning iteration with currentSystems={ ");
105 for (
auto const &sys : currentSystems) {
106 LOGLS_DEBUG(LOGGER,
"Standardizing: " << sys <<
", ");
111 for (
auto connection = firstUnprocessed; connection != connections.
end(); ++connection) {
112 bool related = currentSystems.count(connection->fromSys) > 0;
113 if (!related && currentSystems.count(connection->toSys)) {
114 LOGLS_DEBUG(LOGGER,
"Standardizing: reversing " << (*connection));
116 connection->reverse();
120 if (connection->toSys == connection->fromSys) {
121 std::ostringstream ss;
122 ss <<
"Identity connection found: " << (*connection) <<
".";
123 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.
str());
125 if (knownSystems.
count(connection->toSys)) {
126 std::ostringstream ss;
127 ss <<
"Multiple paths between reference " << reference <<
" and " << connection->toSys
129 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.
str());
131 LOGLS_DEBUG(LOGGER,
"Standardizing: adding " << (*connection));
132 nextSystems.
insert(connection->toSys);
133 knownSystems.
insert(connection->toSys);
134 std::swap(*firstUnprocessed, *connection);
138 currentSystems.swap(nextSystems);
143 if (firstUnprocessed != connections.
end()) {
144 std::ostringstream ss;
145 ss <<
"Disconnected connection(s) found: " << (*firstUnprocessed);
147 for (
auto connection = firstUnprocessed; connection != connections.
end(); ++connection) {
148 ss <<
", " << (*connection);
151 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, ss.
str());
159CameraSys getReferenceSys(std::vector<TransformMap::Connection>
const &connections) {
160 return connections.
front().fromSys;
171 return os << connection.
fromSys <<
"->" << connection.
toSys;
178 for (
auto const &pair : transforms) {
190 new TransformMap(standardizeConnections(reference, connections)));
198 auto mapping = _getMapping(fromSys, toSys);
205 auto mapping = _getMapping(fromSys, toSys);
218int TransformMap::_getFrame(
CameraSys const &system)
const {
220 return _frameIds.
at(system);
223 buffer <<
"Unsupported coordinate system: " << system;
229 CameraSys
const &toSys)
const {
230 return _frameSet->
getMapping(_getFrame(fromSys), _getFrame(toSys));
236 : _connections(
std::move(connections)), _focalPlaneParity(false) {
240 assert(!_connections.empty());
251 _frameIds.
emplace(sys, ++nFrames);
258 _frameSet = std::make_unique<ast::FrameSet>(addFrameForSys(getReferenceSys(_connections)));
260 for (
auto const &connection : _connections) {
261 auto fromSysIdIter = _frameIds.
find(connection.fromSys);
262 assert(fromSysIdIter != _frameIds.
end());
263 _frameSet->
addFrame(fromSysIdIter->second, *connection.transform->getMapping(),
264 addFrameForSys(connection.toSys));
269 assert(_frameSet->
getNFrame() == nFrames);
276 _focalPlaneParity = (jacobian.determinant() < 0);
277 }
catch (pex::exceptions::InvalidParameterError &) {
290 auto result = std::make_unique<ast::FrameSet>(*_frameSet->getFrame(
ast::FrameSet::BASE,
false));
293 fp_frame->setIdent(
"FOCAL_PLANE");
294 fp_frame->setTitle(
"Focal Plane Coordinates");
295 fp_frame->setUnit(1, focalPlaneUnit);
296 fp_frame->setUnit(2, focalPlaneUnit);
297 fp_frame->setLabel(1,
"x");
298 fp_frame->setLabel(2,
"y");
305 *_frameSet->getFrame(old_frame_id,
false)
308 frame->setIdent(
"FIELD_ANGLE");
309 frame->setTitle(
"Field Angle Coordinates");
310 frame->setUnit(1,
"rad");
311 frame->setUnit(2,
"rad");
312 frame->setLabel(1,
"x");
313 frame->setLabel(2,
"y");
315 for (
auto const & detector : detectors) {
317 auto id_iter = _frameIds.find(sys);
318 if (id_iter == _frameIds.end()) {
320 id_iter = _frameIds.find(sys);
321 if (id_iter == _frameIds.end()) {
323 buffer <<
"Unsupported coordinate system: " << sys;
330 *_frameSet->getFrame(id_iter->second,
false)
333 frame->setIdent((boost::format(
"DETECTOR_%03d") % detector->getId()).str());
334 frame->setTitle((boost::format(
"Pixel Coordinates (Detector %d)") % detector->getId()).str());
335 frame->setUnit(1,
"pix");
336 frame->setUnit(2,
"pix");
337 frame->setLabel(1,
"x");
338 frame->setLabel(2,
"y");
339 auto bbox = detector->getBBox();
340 frame->setBottom(1, bbox.getMinX());
341 frame->setTop(1, bbox.getMaxX());
342 frame->setBottom(2, bbox.getMinY());
343 frame->setTop(2, bbox.getMaxY());
350struct PersistenceHelper {
351 static PersistenceHelper
const &get() {
352 static PersistenceHelper
const instance;
370 schema.addField<
std::string>(
"fromSysName",
"Camera coordinate system name.",
"", 0)),
371 fromSysDetectorName(schema.addField<
std::string>(
372 "fromSysDetectorName",
"Camera coordinate system detector name.",
"", 0)),
373 toSysName(schema.addField<
std::string>(
"toSysName",
"Camera coordinate system name.",
"", 0)),
374 toSysDetectorName(schema.addField<
std::string>(
375 "toSysDetectorName",
"Camera coordinate system detector name.",
"", 0)),
376 transform(schema.addField<int>(
"transform",
"Archive ID of the transform.",
"")) {}
378 PersistenceHelper(PersistenceHelper
const &) =
delete;
379 PersistenceHelper(PersistenceHelper &&) =
delete;
381 PersistenceHelper &operator=(PersistenceHelper
const &) =
delete;
382 PersistenceHelper &operator=(PersistenceHelper &&) =
delete;
387struct OldPersistenceHelper {
388 static OldPersistenceHelper
const &get() {
389 static OldPersistenceHelper
const instance;
396 table::Schema sysSchema;
397 table::Key<std::string> sysName;
398 table::Key<std::string> detectorName;
406 table::Schema connectionSchema;
407 table::Key<int> from;
409 table::Key<int> transform;
411 CameraSys makeCameraSys(table::BaseRecord
const &record)
const {
412 return CameraSys(record.get(sysName), record.get(detectorName));
416 OldPersistenceHelper()
418 sysName(sysSchema.addField<std::string>(
"sysName",
"Camera coordinate system name",
"", 0)),
419 detectorName(sysSchema.addField<std::string>(
"detectorName",
420 "Camera coordinate system detector name",
"", 0)),
421 id(sysSchema.addField<
int>(
"id",
"AST ID of the Frame for the CameraSys",
"")),
423 from(connectionSchema.addField<
int>(
"from",
"AST ID of the Frame this transform maps from.",
425 to(connectionSchema.addField<
int>(
"to",
"AST ID of the Frame this transform maps to.",
"")),
426 transform(connectionSchema.addField<
int>(
"transform",
"Archive ID of the transform.",
"")) {}
428 OldPersistenceHelper(OldPersistenceHelper
const &) =
delete;
429 OldPersistenceHelper(OldPersistenceHelper &&) =
delete;
431 OldPersistenceHelper &operator=(OldPersistenceHelper
const &) =
delete;
432 OldPersistenceHelper &operator=(OldPersistenceHelper &&) =
delete;
442 auto const &keys = PersistenceHelper::get();
445 for (
auto const &connection : _connections) {
446 auto record = cat.addNew();
447 record->set(keys.fromSysName, connection.fromSys.getSysName());
448 record->set(keys.fromSysDetectorName, connection.fromSys.getDetectorName());
449 record->set(keys.toSysName, connection.toSys.getSysName());
450 record->set(keys.toSysDetectorName, connection.toSys.getDetectorName());
451 record->set(keys.transform, handle.
put(connection.transform));
461 auto const &keys = OldPersistenceHelper::get();
464 auto const &sysCat = catalogs[0];
465 auto const &connectionCat = catalogs[1];
472 for (
auto const &sysRecord : sysCat) {
473 auto sys = keys.makeCameraSys(sysRecord);
474 sysById.
emplace(sysRecord.get(keys.id), sys);
477 auto const referenceSysIter = sysById.
find(1);
480 for (
auto const &connectionRecord : connectionCat) {
481 auto const fromSysIter = sysById.
find(connectionRecord.get(keys.from));
483 auto const toSysIter = sysById.
find(connectionRecord.get(keys.to));
486 archive.
get<geom::TransformPoint2ToPoint2>(connectionRecord.get(keys.transform));
491 connections = standardizeConnections(referenceSysIter->second,
std::move(connections));
497 if (catalogs.size() == 2u) {
498 return readOld(archive, catalogs);
501 auto const &keys = PersistenceHelper::get();
504 auto const &cat = catalogs[0];
508 for (
auto const &record : cat) {
509 CameraSys const fromSys(record.get(keys.fromSysName), record.get(keys.fromSysDetectorName));
510 CameraSys const toSys(record.get(keys.toSysName), record.get(keys.toSysDetectorName));
511 auto const transform = archive.
get<geom::TransformPoint2ToPoint2>(record.get(keys.transform));
517 auto const referenceSys = getReferenceSys(connections);
518 connections = standardizeConnections(referenceSys,
std::move(connections));
532template 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.
static int constexpr CURRENT
index of current frame
int getNFrame() const
Get FrameSet_NFrame "NFrame": number of Frames in the FrameSet, starting from 1.
static int constexpr BASE
index of base frame
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,...
CameraSysPrefix const PIXELS
Pixel coordinates: Nominal position on the entry surface of a given detector (x, y unbinned pixels).
std::ostream & operator<<(std::ostream &os, CameraSysPrefix const &detSysPrefix)
CameraSysPrefix const ACTUAL_PIXELS
The actual pixels where the photon lands and electrons are generated (x,y unbinned) This takes into a...
Point< double, 2 > Point2D
T throw_with_nested(T... args)