lsst.geom g19811a7679+250889e214
Loading...
Searching...
No Matches
SphereTransform.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 <iostream>
23
24#include "boost/format.hpp"
25#include "ndarray/eigen.h"
26#include "Eigen/SVD"
27#include "Eigen/LU"
28
29#include "lsst/pex/exceptions.h"
32
33namespace lsst {
34namespace geom {
35
36SphereTransform::SphereTransform() noexcept : _matrix(Matrix::Identity()) {}
37
38SphereTransform::SphereTransform(Matrix const& matrix) noexcept : _matrix(matrix) {}
39
40SphereTransform SphereTransform::fit_unit_vectors(ndarray::Array<double const, 2> const& from,
41 ndarray::Array<double const, 2> const& to,
42 ndarray::Array<double const, 1> const& weights) {
43 if (from.getSize<0>() != to.getSize<0>()) {
45 (boost::format("'from' array first dimension (%d) does not match 'to' array first "
46 "dimension (%d).") %
47 from.getSize<0>() % to.getSize<0>())
48 .str());
49 }
50 if (from.getSize<1>() != 3) {
51 throw LSST_EXCEPT(
53 (boost::format("'from' array second dimension size must be 3; got %d.") % from.getSize<1>())
54 .str());
55 }
56 if (to.getSize<1>() != 3) {
57 throw LSST_EXCEPT(
59 (boost::format("'to' array second dimension size must be 3; got %d.") % to.getSize<1>())
60 .str());
61 }
62 Eigen::Matrix<double, Eigen::Dynamic, 3> y = ndarray::asEigenMatrix(to);
63 Eigen::Matrix<double, Eigen::Dynamic, 3> x = ndarray::asEigenMatrix(from);
64 if (!weights.isEmpty()) {
65 auto w = ndarray::asEigenMatrix(weights);
66 y.array().colwise() *= w.array();
67 }
68 Eigen::JacobiSVD<Eigen::Matrix3d> svd(x.transpose() * y, Eigen::ComputeFullU | Eigen::ComputeFullV);
69 Eigen::Matrix3d u_t = svd.matrixU().transpose();
70 Matrix result = svd.matrixV() * u_t;
71 if (result.determinant() < 0) {
72 // We need the result to be a rotation matrix, but SVD only guarantees
73 // an orthogonal one. If the determinant is negative (i.e. there's a
74 // reflection), fix it.
75 u_t.row(2) *= -1.0;
76 result = svd.matrixV() * u_t;
77 }
78 return SphereTransform(result);
79}
80
82 return SphereTransform(_matrix * other._matrix);
83}
84
86 return SpherePoint(this->operator()(point.getVector()));
87}
88
90 Eigen::Vector3d v = _matrix * asEigen(vector);
91 return sphgeom::UnitVector3d(v.x(), v.y(), v.z());
92}
93
94double SphereTransform::applyX(double x, double y, double z) const noexcept {
95 return _matrix.row(0).dot(Eigen::Vector3d(x, y, z));
96}
97double SphereTransform::applyY(double x, double y, double z) const noexcept {
98 return _matrix.row(1).dot(Eigen::Vector3d(x, y, z));
99}
100double SphereTransform::applyZ(double x, double y, double z) const noexcept {
101 return _matrix.row(2).dot(Eigen::Vector3d(x, y, z));
102}
103
105 return SphereTransform(_matrix.transpose());
106}
107
108} // namespace geom
109} // namespace lsst
#define LSST_EXCEPT(type,...)
Point in an unspecified spherical coordinate system.
Definition SpherePoint.h:57
SpherePoint() noexcept
Construct a SpherePoint with "nan" for longitude and latitude.
double applyY(double x, double y, double z) const noexcept
SphereTransform() noexcept
Construct an empty (identity) SphereTransform.
SphereTransform const inverted() const noexcept
Return the inverse transform.
Eigen::Matrix< double, 3, 3, Eigen::DontAlign > Matrix
static SphereTransform fit_unit_vectors(ndarray::Array< double const, 2 > const &from, ndarray::Array< double const, 2 > const &to, ndarray::Array< double const, 1 > const &weights=ndarray::Array< double const, 1 >())
Fit for the transform that best maps (in a least-squares sense) one set of unit vectors onto another.
SphereTransform operator*(SphereTransform const &other) const noexcept
Compose two transforms.
SpherePoint operator()(SpherePoint const &point) const noexcept
Apply the transform to a SpherePoint.
double applyZ(double x, double y, double z) const noexcept
double applyX(double x, double y, double z) const noexcept
Transform a 3-d unit vector given and returned as separate double values.
Eigen::Vector3d asEigen(sphgeom::Vector3d const &vector) noexcept