Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/ceres/include/ceres/line_manifold.h')
-rw-r--r--extern/ceres/include/ceres/line_manifold.h304
1 files changed, 304 insertions, 0 deletions
diff --git a/extern/ceres/include/ceres/line_manifold.h b/extern/ceres/include/ceres/line_manifold.h
new file mode 100644
index 00000000000..f8f1b235220
--- /dev/null
+++ b/extern/ceres/include/ceres/line_manifold.h
@@ -0,0 +1,304 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2022 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: jodebo_beck@gmx.de (Johannes Beck)
+//
+
+#ifndef CERES_PUBLIC_LINE_MANIFOLD_H_
+#define CERES_PUBLIC_LINE_MANIFOLD_H_
+
+#include <Eigen/Core>
+#include <algorithm>
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
+#include "ceres/internal/householder_vector.h"
+#include "ceres/internal/sphere_manifold_functions.h"
+#include "ceres/manifold.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+// This provides a manifold for lines, where the line is
+// over-parameterized by an origin point and a direction vector. So the
+// parameter vector size needs to be two times the ambient space dimension,
+// where the first half is interpreted as the origin point and the second half
+// as the direction.
+//
+// The plus operator for the line direction is the same as for the
+// SphereManifold. The update of the origin point is
+// perpendicular to the line direction before the update.
+//
+// This manifold is a special case of the affine Grassmannian
+// manifold (see https://en.wikipedia.org/wiki/Affine_Grassmannian_(manifold))
+// for the case Graff_1(R^n).
+//
+// The class works with dynamic and static ambient space dimensions. If the
+// ambient space dimensions is known at compile time use
+//
+// LineManifold<3> manifold;
+//
+// If the ambient space dimensions is not known at compile time the template
+// parameter needs to be set to ceres::DYNAMIC and the actual dimension needs
+// to be provided as a constructor argument:
+//
+// LineManifold<ceres::DYNAMIC> manifold(ambient_dim);
+//
+template <int AmbientSpaceDimension>
+class LineManifold final : public Manifold {
+ public:
+ static_assert(AmbientSpaceDimension == DYNAMIC || AmbientSpaceDimension >= 2,
+ "The ambient space must be at least 2.");
+ static_assert(ceres::DYNAMIC == Eigen::Dynamic,
+ "ceres::DYNAMIC needs to be the same as Eigen::Dynamic.");
+
+ LineManifold();
+ explicit LineManifold(int size);
+
+ int AmbientSize() const override { return 2 * size_; }
+ int TangentSize() const override { return 2 * (size_ - 1); }
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override;
+ bool PlusJacobian(const double* x, double* jacobian) const override;
+ bool Minus(const double* y,
+ const double* x,
+ double* y_minus_x) const override;
+ bool MinusJacobian(const double* x, double* jacobian) const override;
+
+ private:
+ static constexpr bool IsDynamic = (AmbientSpaceDimension == ceres::DYNAMIC);
+ static constexpr int TangentSpaceDimension =
+ IsDynamic ? ceres::DYNAMIC : AmbientSpaceDimension - 1;
+
+ static constexpr int DAmbientSpaceDimension =
+ IsDynamic ? ceres::DYNAMIC : 2 * AmbientSpaceDimension;
+ static constexpr int DTangentSpaceDimension =
+ IsDynamic ? ceres::DYNAMIC : 2 * TangentSpaceDimension;
+
+ using AmbientVector = Eigen::Matrix<double, AmbientSpaceDimension, 1>;
+ using TangentVector = Eigen::Matrix<double, TangentSpaceDimension, 1>;
+ using MatrixPlusJacobian = Eigen::Matrix<double,
+ DAmbientSpaceDimension,
+ DTangentSpaceDimension,
+ Eigen::RowMajor>;
+ using MatrixMinusJacobian = Eigen::Matrix<double,
+ DTangentSpaceDimension,
+ DAmbientSpaceDimension,
+ Eigen::RowMajor>;
+
+ const int size_{AmbientSpaceDimension};
+};
+
+template <int AmbientSpaceDimension>
+LineManifold<AmbientSpaceDimension>::LineManifold()
+ : size_{AmbientSpaceDimension} {
+ static_assert(
+ AmbientSpaceDimension != Eigen::Dynamic,
+ "The size is set to dynamic. Please call the constructor with a size.");
+}
+
+template <int AmbientSpaceDimension>
+LineManifold<AmbientSpaceDimension>::LineManifold(int size) : size_{size} {
+ if (AmbientSpaceDimension != Eigen::Dynamic) {
+ CHECK_EQ(AmbientSpaceDimension, size)
+ << "Specified size by template parameter differs from the supplied "
+ "one.";
+ } else {
+ CHECK_GT(size_, 1)
+ << "The size of the manifold needs to be greater than 1.";
+ }
+}
+
+template <int AmbientSpaceDimension>
+bool LineManifold<AmbientSpaceDimension>::Plus(const double* x_ptr,
+ const double* delta_ptr,
+ double* x_plus_delta_ptr) const {
+ // We seek a box plus operator of the form
+ //
+ // [o*, d*] = Plus([o, d], [delta_o, delta_d])
+ //
+ // where o is the origin point, d is the direction vector, delta_o is
+ // the delta of the origin point and delta_d the delta of the direction and
+ // o* and d* is the updated origin point and direction.
+ //
+ // We separate the Plus operator into the origin point and directional part
+ // d* = Plus_d(d, delta_d)
+ // o* = Plus_o(o, d, delta_o)
+ //
+ // The direction update function Plus_d is the same as as the SphereManifold:
+ //
+ // d* = H_{v(d)} [0.5 sinc(0.5 |delta_d|) delta_d, cos(0.5 |delta_d|)]^T
+ //
+ // where H is the householder matrix
+ // H_{v} = I - (2 / |v|^2) v v^T
+ // and
+ // v(d) = d - sign(d_n) |d| e_n.
+ //
+ // The origin point update function Plus_o is defined as
+ //
+ // o* = o + H_{v(d)} [0.5 delta_o, 0]^T.
+
+ Eigen::Map<const AmbientVector> o(x_ptr, size_);
+ Eigen::Map<const AmbientVector> d(x_ptr + size_, size_);
+
+ Eigen::Map<const TangentVector> delta_o(delta_ptr, size_ - 1);
+ Eigen::Map<const TangentVector> delta_d(delta_ptr + size_ - 1, size_ - 1);
+ Eigen::Map<AmbientVector> o_plus_delta(x_plus_delta_ptr, size_);
+ Eigen::Map<AmbientVector> d_plus_delta(x_plus_delta_ptr + size_, size_);
+
+ const double norm_delta_d = delta_d.norm();
+
+ o_plus_delta = o;
+
+ // Shortcut for zero delta direction.
+ if (norm_delta_d == 0.0) {
+ d_plus_delta = d;
+
+ if (delta_o.isZero(0.0)) {
+ return true;
+ }
+ }
+
+ // Calculate the householder transformation which is needed for f_d and f_o.
+ AmbientVector v(size_);
+ double beta;
+
+ // NOTE: The explicit template arguments are needed here because
+ // ComputeHouseholderVector is templated and some versions of MSVC
+ // have trouble deducing the type of v automatically.
+ internal::ComputeHouseholderVector<Eigen::Map<const AmbientVector>,
+ double,
+ AmbientSpaceDimension>(d, &v, &beta);
+
+ if (norm_delta_d != 0.0) {
+ internal::ComputeSphereManifoldPlus(
+ v, beta, d, delta_d, norm_delta_d, &d_plus_delta);
+ }
+
+ // The null space is in the direction of the line, so the tangent space is
+ // perpendicular to the line direction. This is achieved by using the
+ // householder matrix of the direction and allow only movements
+ // perpendicular to e_n.
+ //
+ // The factor of 0.5 is used to be consistent with the line direction
+ // update.
+ AmbientVector y(size_);
+ y << 0.5 * delta_o, 0;
+ o_plus_delta += internal::ApplyHouseholderVector(y, v, beta);
+
+ return true;
+}
+
+template <int AmbientSpaceDimension>
+bool LineManifold<AmbientSpaceDimension>::PlusJacobian(
+ const double* x_ptr, double* jacobian_ptr) const {
+ Eigen::Map<const AmbientVector> d(x_ptr + size_, size_);
+ Eigen::Map<MatrixPlusJacobian> jacobian(
+ jacobian_ptr, 2 * size_, 2 * (size_ - 1));
+
+ // Clear the Jacobian as only half of the matrix is not zero.
+ jacobian.setZero();
+
+ auto jacobian_d =
+ jacobian
+ .template topLeftCorner<AmbientSpaceDimension, TangentSpaceDimension>(
+ size_, size_ - 1);
+ auto jacobian_o = jacobian.template bottomRightCorner<AmbientSpaceDimension,
+ TangentSpaceDimension>(
+ size_, size_ - 1);
+ internal::ComputeSphereManifoldPlusJacobian(d, &jacobian_d);
+ jacobian_o = jacobian_d;
+ return true;
+}
+
+template <int AmbientSpaceDimension>
+bool LineManifold<AmbientSpaceDimension>::Minus(const double* y_ptr,
+ const double* x_ptr,
+ double* y_minus_x) const {
+ Eigen::Map<const AmbientVector> y_o(y_ptr, size_);
+ Eigen::Map<const AmbientVector> y_d(y_ptr + size_, size_);
+ Eigen::Map<const AmbientVector> x_o(x_ptr, size_);
+ Eigen::Map<const AmbientVector> x_d(x_ptr + size_, size_);
+
+ Eigen::Map<TangentVector> y_minus_x_o(y_minus_x, size_ - 1);
+ Eigen::Map<TangentVector> y_minus_x_d(y_minus_x + size_ - 1, size_ - 1);
+
+ AmbientVector v(size_);
+ double beta;
+
+ // NOTE: The explicit template arguments are needed here because
+ // ComputeHouseholderVector is templated and some versions of MSVC
+ // have trouble deducing the type of v automatically.
+ internal::ComputeHouseholderVector<Eigen::Map<const AmbientVector>,
+ double,
+ AmbientSpaceDimension>(x_d, &v, &beta);
+
+ internal::ComputeSphereManifoldMinus(v, beta, x_d, y_d, &y_minus_x_d);
+
+ AmbientVector delta_o = y_o - x_o;
+ const AmbientVector h_delta_o =
+ 2.0 * internal::ApplyHouseholderVector(delta_o, v, beta);
+ y_minus_x_o = h_delta_o.template head<TangentSpaceDimension>(size_ - 1);
+
+ return true;
+}
+
+template <int AmbientSpaceDimension>
+bool LineManifold<AmbientSpaceDimension>::MinusJacobian(
+ const double* x_ptr, double* jacobian_ptr) const {
+ Eigen::Map<const AmbientVector> d(x_ptr + size_, size_);
+ Eigen::Map<MatrixMinusJacobian> jacobian(
+ jacobian_ptr, 2 * (size_ - 1), 2 * size_);
+
+ // Clear the Jacobian as only half of the matrix is not zero.
+ jacobian.setZero();
+
+ auto jacobian_d =
+ jacobian
+ .template topLeftCorner<TangentSpaceDimension, AmbientSpaceDimension>(
+ size_ - 1, size_);
+ auto jacobian_o = jacobian.template bottomRightCorner<TangentSpaceDimension,
+ AmbientSpaceDimension>(
+ size_ - 1, size_);
+ internal::ComputeSphereManifoldMinusJacobian(d, &jacobian_d);
+ jacobian_o = jacobian_d;
+
+ return true;
+}
+
+} // namespace ceres
+
+// clang-format off
+#include "ceres/internal/reenable_warnings.h"
+// clang-format on
+
+#endif // CERES_PUBLIC_LINE_MANIFOLD_H_