LSST Applications g04e9c324dd+8c5ae1fdc5,g134cb467dc+1b3060144d,g18429d2f64+f642bf4753,g199a45376c+0ba108daf9,g1fd858c14a+2dcf163641,g262e1987ae+7b8c96d2ca,g29ae962dfc+3bd6ecb08a,g2cef7863aa+aef1011c0b,g35bb328faa+8c5ae1fdc5,g3fd5ace14f+53e1a9e7c5,g4595892280+fef73a337f,g47891489e3+2efcf17695,g4d44eb3520+642b70b07e,g53246c7159+8c5ae1fdc5,g67b6fd64d1+2efcf17695,g67fd3c3899+b70e05ef52,g74acd417e5+317eb4c7d4,g786e29fd12+668abc6043,g87389fa792+8856018cbb,g89139ef638+2efcf17695,g8d7436a09f+3be3c13596,g8ea07a8fe4+9f5ccc88ac,g90f42f885a+a4e7b16d9b,g97be763408+ad77d7208f,g9dd6db0277+b70e05ef52,ga681d05dcb+a3f46e7fff,gabf8522325+735880ea63,gac2eed3f23+2efcf17695,gb89ab40317+2efcf17695,gbf99507273+8c5ae1fdc5,gd8ff7fe66e+b70e05ef52,gdab6d2f7ff+317eb4c7d4,gdc713202bf+b70e05ef52,gdfd2d52018+b10e285e0f,ge365c994fd+310e8507c4,ge410e46f29+2efcf17695,geaed405ab2+562b3308c0,gffca2db377+8c5ae1fdc5,w.2025.35
LSST Data Management Base Package
Loading...
Searching...
No Matches
Camera.cc
Go to the documentation of this file.
1/*
2 * Developed for the LSST Data Management System.
3 * This product includes software developed by the LSST Project
4 * (https://www.lsst.org).
5 * See the COPYRIGHT file at the top-level directory of this distribution
6 * for details of code ownership.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <Eigen/LU>
23
24#include "lsst/geom/Point.h"
33
34namespace lsst {
35namespace afw {
36namespace cameraGeom {
37
38namespace {
39
40// Set this as a function to ensure FOCAL_PLANE is defined before use.
41CameraSys const getNativeCameraSys() { return FOCAL_PLANE; }
42
43} // namespace
44
45Camera::~Camera() noexcept = default;
46
47Camera::Builder Camera::rebuild() const { return Camera::Builder(*this); }
48
50 CameraSys const &cameraSys) const {
51 auto nativePoint = transform(point, cameraSys, getNativeCameraSys());
52
53 DetectorList detectorList;
54 for (auto const &item : getIdMap()) {
55 auto detector = item.second;
56 auto pointPixels = detector->transform(nativePoint, getNativeCameraSys(), PIXELS);
57 if (lsst::geom::Box2D(detector->getBBox()).contains(pointPixels)) {
58 detectorList.push_back(std::move(detector));
59 }
60 }
61 return detectorList;
62}
63
65 CameraSys const &cameraSys) const {
66 std::vector<DetectorList> detectorListList(pointList.size());
67 auto nativePointList = transform(pointList, cameraSys, getNativeCameraSys());
68
69 for (auto const &item : getIdMap()) {
70 auto const &detector = item.second;
71 auto pointPixelsList = detector->transform(nativePointList, getNativeCameraSys(), PIXELS);
72 for (std::size_t i = 0; i < pointPixelsList.size(); ++i) {
73 auto const &pointPixels = pointPixelsList[i];
74 if (lsst::geom::Box2D(detector->getBBox()).contains(pointPixels)) {
75 detectorListList[i].push_back(detector);
76 }
77 }
78 }
79 return detectorListList;
80}
81
83 CameraSys const &toSys) const {
84 return getTransformMap()->getTransform(fromSys, toSys);
85}
86
88 CameraSys const &toSys) const {
89 auto transform = getTransform(fromSys, toSys);
90 return transform->applyForward(point);
91}
92
94 CameraSys const &fromSys, CameraSys const &toSys) const {
95 auto transform = getTransform(fromSys, toSys);
96 return transform->applyForward(points);
97}
98
99std::shared_ptr<Detector::InCameraBuilder> Camera::makeDetectorBuilder(std::string const &name, int id) {
101}
102
103std::shared_ptr<Detector::InCameraBuilder> Camera::makeDetectorBuilder(Detector const &detector) {
104 return std::shared_ptr<Detector::InCameraBuilder>(new Detector::InCameraBuilder(detector));
105}
106
107std::vector<TransformMap::Connection> const &Camera::getDetectorBuilderConnections(
108 Detector::InCameraBuilder const &detector) {
109 return detector._connections;
110}
111
112namespace {
113
114class PersistenceHelper {
115public:
116 static PersistenceHelper const &get() {
117 static PersistenceHelper const instance;
118 return instance;
119 }
120
121 table::Schema schema;
122 table::Key<std::string> name;
123 table::Key<std::string> pupilFactoryName;
124 table::Key<int> transformMap;
125
126private:
127 PersistenceHelper()
128 : schema(),
129 name(schema.addField<std::string>("name", "Camera name", "", 0)),
130 pupilFactoryName(schema.addField<std::string>(
131 "pupilFactoryName", "Fully-qualified name of a Python PupilFactory class", "", 0)),
132 transformMap(schema.addField<int>("transformMap", "archive ID for Camera's TransformMap")) {}
133
134 PersistenceHelper(PersistenceHelper const &) = delete;
135 PersistenceHelper(PersistenceHelper &&) = delete;
136
137 PersistenceHelper &operator=(PersistenceHelper const &) = delete;
138 PersistenceHelper &operator=(PersistenceHelper &&) = delete;
139};
140
141} // namespace
142
145 auto const &keys = PersistenceHelper::get();
146 auto cat = handle.makeCatalog(keys.schema);
147 auto record = cat.addNew();
148 record->set(keys.name, getName());
149 record->set(keys.pupilFactoryName, getPupilFactoryName());
150 record->set(keys.transformMap, handle.put(getTransformMap()));
151 handle.saveCatalog(cat);
152}
153
155public:
156 Factory() : table::io::PersistableFactory("Camera") {}
157
159 CatalogVector const &catalogs) const override {
160 // can't use make_shared because ctor is protected
161 return std::shared_ptr<Camera>(new Camera(archive, catalogs));
162 }
163
164 static Factory const registration;
165};
166
168
169Camera::Camera(std::string const &name, DetectorList detectors,
170 std::shared_ptr<TransformMap const> transformMap, std::string const &pupilFactoryName)
171 : DetectorCollection(std::move(detectors)),
172 _name(name),
173 _pupilFactoryName(pupilFactoryName),
174 _transformMap(std::move(transformMap)) {}
175
177 : DetectorCollection(archive, catalogs)
178// deferred initalization for data members is not ideal, but better than
179// trying to initialize them before validating the archive
180{
181 auto const &keys = PersistenceHelper::get();
182 LSST_ARCHIVE_ASSERT(catalogs.size() >= 2u);
183 auto const &cat = catalogs[1];
184 LSST_ARCHIVE_ASSERT(cat.getSchema() == keys.schema);
185 LSST_ARCHIVE_ASSERT(cat.size() == 1u);
186 auto const &record = cat.front();
187 _name = record.get(keys.name);
188 _pupilFactoryName = record.get(keys.pupilFactoryName);
189 _transformMap = archive.get<TransformMap>(record.get(keys.transformMap));
190}
191
192std::string Camera::getPersistenceName() const { return "Camera"; }
193
194Camera::Builder::Builder(std::string const &name) : _name(name), _pupilFactoryName(), _focalPlaneParity(false) {}
195
197 : _name(camera.getName()), _pupilFactoryName(camera.getPupilFactoryName()), _focalPlaneParity(false) {
198 // Add Detector Builders for all Detectors; does not (yet) include
199 // coordinate transform information.
200 for (auto const &pair : camera.getIdMap()) {
201 BaseCollection::add(Camera::makeDetectorBuilder(*pair.second));
202 }
203 // Iterate over connections in TransformMap, distributing them between the
204 // Camera Builder and the Detector Builders.
205 for (auto const &connection : camera.getTransformMap()->getConnections()) {
206 // asserts below are on Detector, Camera, and TransformMap invariants:
207 // - Connections should always be from native sys to something else.
208 // - The only connections between full-camera and per-detector sys
209 // should be from the camera native sys (FOCAL_PLANE) to the
210 // detector native sys (PIXELS).
211 // - When TransformMap standardizes connections, it should maintain
212 // these directions, as that's consistent with "pointing away" from
213 // the overall reference sys (the camera native sys).
214 if (connection.fromSys.hasDetectorName()) {
215 assert(connection.toSys.getDetectorName() == connection.fromSys.getDetectorName());
216 auto detector = (*this)[connection.fromSys.getDetectorName()];
217 assert(connection.fromSys == detector->getNativeCoordSys());
218 detector->setTransformFromPixelsTo(CameraSysPrefix(connection.toSys.getSysName()),
219 connection.transform);
220 } else {
221 assert(connection.fromSys == getNativeCameraSys());
222 if (!connection.toSys.hasDetectorName()) {
223 _connections.push_back(connection);
224 }
225 // We ignore the FOCAL_PLANE to PIXELS transforms transforms, as
226 // those are always regenerated from the Orientation when we
227 // rebuild the Camera.
228 }
229 }
230}
231
232Camera::Builder::~Builder() noexcept = default;
233
234void Camera::Builder::setFocalPlaneParity(bool flipX) { _focalPlaneParity = flipX; }
235
237 // Make a big vector of all coordinate transform connections;
238 // start with general transforms for the camera as a whole:
239 std::vector<TransformMap::Connection> connections(_connections);
240 // Check that the FOCAL_PLANE <-> FIELD_ANGLE transform is consistent with
241 // the set parity, and add an x-axis flip if not.
242 auto field_angle_connection =
243 std::find_if(connections.begin(), connections.end(), [](TransformMap::Connection const &c) {
244 return c.fromSys == FOCAL_PLANE && c.toSys == FIELD_ANGLE;
245 });
246 if (field_angle_connection != connections.end()) {
247 auto jacobian = field_angle_connection->transform->getJacobian(lsst::geom::Point2D(0.0, 0.0));
248 if ((jacobian.determinant() < 0) != _focalPlaneParity) {
249 field_angle_connection->transform =
250 field_angle_connection->transform->then(*afw::geom::makeTransform(
252 }
253 }
254 // Loop over detectors and add the transforms from FOCAL_PLANE
255 // to PIXELS (via the Orientation), and then any extra transforms
256 // from PIXELS to other things.
257 for (auto const &pair : getIdMap()) {
258 auto const &detectorBuilder = *pair.second;
259 std::vector<TransformMap::Connection> detectorConnections =
260 getDetectorBuilderConnections(detectorBuilder);
261 std::vector<std::vector<CameraSys>> allDetConnections;
262 for (auto const &connection : detectorConnections) {
263 std::vector<CameraSys> tmpConnection = {connection.fromSys, connection.toSys};
264 allDetConnections.push_back(tmpConnection);
265 }
266 std::vector<CameraSys> connection = {detectorBuilder.getNativeCoordSys(), getNativeCameraSys()};
267 std::vector<CameraSys> invConnection = {getNativeCameraSys(), detectorBuilder.getNativeCoordSys()};
268 if ((std::find(allDetConnections.begin(), allDetConnections.end(), connection) ==
269 allDetConnections.end()) &&
270 (std::find(allDetConnections.begin(), allDetConnections.end(), invConnection) ==
271 allDetConnections.end())) {
273 detectorBuilder.getOrientation().makeFpPixelTransform(detectorBuilder.getPixelSize()),
274 getNativeCameraSys(), detectorBuilder.getNativeCoordSys()});
275 }
276 connections.insert(connections.end(), getDetectorBuilderConnections(detectorBuilder).begin(),
277 getDetectorBuilderConnections(detectorBuilder).end());
278 }
279 // Make a single big TransformMap.
280 auto transformMap = TransformMap::make(getNativeCameraSys(), connections);
281 // Make actual Detector objects, giving each the full TransformMap.
282 DetectorList detectors;
283 detectors.reserve(size());
284 for (auto const &pair : getIdMap()) {
285 auto const &detectorBuilder = *pair.second;
286 detectors.push_back(detectorBuilder.finish(transformMap));
287 }
289 new Camera(_name, std::move(detectors), std::move(transformMap), _pupilFactoryName));
290}
291
292namespace {
293
294// Return the first connection in the given range that has toSys as its "to"
295// endpoint.
296//
297// @tparam Iter Iterator that dereferences to `Connection const &`.
298//
299template <typename Iter>
300Iter findConnection(Iter first, Iter last, CameraSys const &toSys) {
301 return std::find_if(first, last, [&toSys](auto const &connection) { return connection.toSys == toSys; });
302}
303
304} // namespace
305
308 if (toSys.hasDetectorName()) {
310 (boost::format("%s should be added to Detector %s, not Camera") %
311 toSys.getSysName() % toSys.getDetectorName())
312 .str());
313 }
314 auto iter = findConnection(_connections.begin(), _connections.end(), toSys);
315 if (iter == _connections.end()) {
316 _connections.push_back(TransformMap::Connection{transform, getNativeCameraSys(), toSys});
317 } else {
318 iter->transform = transform;
319 }
320}
321
323 auto iter = findConnection(_connections.begin(), _connections.end(), toSys);
324 if (iter != _connections.end()) {
325 _connections.erase(iter);
326 return true;
327 }
328 return false;
329}
330
332 auto detector = makeDetectorBuilder(name, id);
333 BaseCollection::add(detector);
334 return detector;
335}
336
337} // namespace cameraGeom
338
339namespace table {
340namespace io {
341
342template class PersistableFacade<cameraGeom::Camera>;
343
344} // namespace io
345} // namespace table
346
347} // namespace afw
348} // namespace lsst
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition Exception.h:48
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition Persistable.h:48
T begin(T... args)
A helper class for creating and modifying cameras.
Definition Camera.h:210
void setTransformFromFocalPlaneTo(CameraSys const &toSys, std::shared_ptr< afw::geom::TransformPoint2ToPoint2 const > transform)
Set the transformation from FOCAL_PLANE to the given coordinate system.
Definition Camera.cc:306
Builder(std::string const &name)
Construct a Builder for a completely new Camera with the given name.
Definition Camera.cc:194
std::string getName() const
Return the name of the camera.
Definition Camera.h:232
void setFocalPlaneParity(bool flipX)
Set whether an x-axis flip should be included in the FOCAL_PLANE to FIELD_ANGLE transform.
Definition Camera.cc:234
std::string getPupilFactoryName() const
Return the fully-qualified name of the Python class that provides this Camera's PupilFactory.
Definition Camera.h:238
std::shared_ptr< Detector::InCameraBuilder > add(std::string const &name, int id)
Add a new Detector with the given name and ID.
Definition Camera.cc:331
bool discardTransformFromFocalPlaneTo(CameraSys const &toSys)
Remove any transformation from FOCAL_PLANE to the given coordinate system.
Definition Camera.cc:322
std::shared_ptr< Camera const > finish() const
Construct a new Camera from the state of the Builder.
Definition Camera.cc:236
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.
Definition Camera.cc:158
static Factory const registration
Definition Camera.cc:164
Camera(Camera const &)=delete
DetectorCollection::List DetectorList
Definition Camera.h:46
Camera::Builder rebuild() const
Create a Camera::Builder object initialized with this camera's state.
Definition Camera.cc:47
std::shared_ptr< TransformMap const > getTransformMap() const noexcept
Obtain the transform registry.
Definition Camera.h:127
std::string getPupilFactoryName() const
Return the fully-qualified name of the Python class that provides this Camera's PupilFactory.
Definition Camera.h:74
std::string getName() const
Return the name of the camera.
Definition Camera.h:69
DetectorList findDetectors(lsst::geom::Point2D const &point, CameraSys const &cameraSys) const
Find the detectors that cover a point in any camera system.
Definition Camera.cc:49
virtual ~Camera() noexcept
std::vector< DetectorList > findDetectorsList(std::vector< lsst::geom::Point2D > const &pointList, CameraSys const &cameraSys) const
Find the detectors that cover a list of points in any camera system.
Definition Camera.cc:64
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
Definition Camera.cc:192
lsst::geom::Point2D transform(lsst::geom::Point2D const &point, CameraSys const &fromSys, CameraSys const &toSys) const
Transform a point from one camera coordinate system to another.
Definition Camera.cc:87
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
Definition Camera.cc:143
std::shared_ptr< afw::geom::TransformPoint2ToPoint2 > getTransform(CameraSys const &fromSys, CameraSys const &toSys) const
Get a transform from one CameraSys to another.
Definition Camera.cc:82
Camera coordinate system; used as a key in in TransformMap.
Definition CameraSys.h:83
bool hasDetectorName() const noexcept
Does this have a non-blank detector name?
Definition CameraSys.h:125
std::string getSysName() const
Get coordinate system name.
Definition CameraSys.h:115
std::string getDetectorName() const
Get detector name, or "" if not a detector-specific coordinate system.
Definition CameraSys.h:120
A helper class that allows the properties of a detector to be modified in the course of modifying a f...
Definition Detector.h:554
IdMap const & getIdMap() const noexcept
Get a map keyed and ordered by ID.
void add(std::shared_ptr< Detector::InCameraBuilder > detector)
An immutable collection of Detectors that can be accessed by name or ID.
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
A registry of 2-dimensional coordinate transforms for a specific camera.
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.
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
Definition Catalog.h:490
A vector of catalogs used by Persistable.
A multi-catalog archive object used to load table::io::Persistable objects.
std::shared_ptr< Persistable > get(int id) const
Load the Persistable with the given ID and return it.
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.
PersistableFactory(std::string const &name)
Constructor for the factory.
io::OutputArchiveHandle OutputArchiveHandle
An affine coordinate transformation consisting of a linear transformation and an offset.
A floating-point coordinate rectangle geometry.
Definition Box.h:413
bool contains(Point2D const &point) const noexcept
Return true if the box contains the point.
Definition Box.cc:322
static LinearTransform makeScaling(double s) noexcept
Reports errors in the logical structure of the program.
Definition Runtime.h:46
T end(T... args)
T find_if(T... args)
T insert(T... args)
T move(T... args)
CameraSys const FOCAL_PLANE
Focal plane coordinates: Position on a 2-d planar approximation to the focal plane (x,...
Definition CameraSys.cc:30
CameraSysPrefix const PIXELS
Pixel coordinates: Nominal position on the entry surface of a given detector (x, y unbinned pixels).
Definition CameraSys.cc:34
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Wrap an lsst::geom::AffineTransform as a Transform.
Point< double, 2 > Point2D
Definition Point.h:324
STL namespace.
T push_back(T... args)
T reserve(T... args)
T size(T... args)
Representation of a single edge in the graph defined by a TransformMap.