lsst.geom g19811a7679+c67ce918b9
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
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