1+ // MIT License
2+
3+ // Copyright (c) 2025 Easton Potokar, Taylor Pool, and Michael Kaess
4+
5+ // Permission is hereby granted, free of charge, to any person obtaining a copy
6+ // of this software and associated documentation files (the "Software"), to deal
7+ // in the Software without restriction, including without limitation the rights
8+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+ // copies of the Software, and to permit persons to whom the Software is
10+ // furnished to do so, subject to the following conditions:
11+
12+ // The above copyright notice and this permission notice shall be included in all
13+ // copies or substantial portions of the Software.
14+
15+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+ // SOFTWARE.
122#pragma once
223
324#include < gtsam/geometry/Point3.h>
@@ -17,82 +38,131 @@ static void check(const gtsam::SharedNoiseModel &noiseModel, size_t m) {
1738
1839using OptionalJacobian = gtsam::OptionalJacobian<Eigen::Dynamic, Eigen::Dynamic>;
1940
41+ // / @brief Structure that holds plane-point correspondences and computes their error
42+ // /
43+ // / Points and normals are stored in a std::vector that is then mapped to Eigen
44+ // / matrices for efficient computation.
2045struct PlanePoint {
46+ // / @brief Shared pointer type
2147 typedef std::shared_ptr<PlanePoint> Ptr;
2248
49+ // / @brief Vectors to hold point and normal data
2350 std::vector<double > p_i;
2451 std::vector<double > n_i;
2552 std::vector<double > p_j;
2653
2754 PlanePoint () = default ;
2855
56+ // / @brief Add a new plane-point correspondence
2957 void push_back (const PlanarFeat &p_i_, const PlanarFeat &p_j_) {
3058 p_i.insert (p_i.end (), {p_i_.x , p_i_.y , p_i_.z });
3159 n_i.insert (n_i.end (), {p_i_.nx , p_i_.ny , p_i_.nz });
3260 p_j.insert (p_j.end (), {p_j_.x , p_j_.y , p_j_.z });
3361 }
3462
63+ // / @brief Clear all stored correspondences
3564 void clear () noexcept {
3665 p_i.clear ();
3766 n_i.clear ();
3867 p_j.clear ();
3968 }
4069
70+ // / @brief Get the number of residuals (one per correspondence)
4171 size_t num_residuals () const noexcept { return p_i.size () / 3 ; }
72+
73+ // / @brief Get the number of constraints / correspondences
4274 size_t num_constraints () const noexcept { return p_i.size () / 3 ; }
4375
76+ // / @brief Evaluate the residual given two poses
77+ // /
78+ // / @param Ti The pose of the first frame
79+ // / @param Tj The pose of the second frame
80+ // / @param residual_D_Ti Optional Jacobian of the residual w.r.t. Ti
81+ // / @param residual_D_Tj Optional Jacobian of the residual w.r.t. Tj
82+ // / @return The residual vector
4483 [[nodiscard]] gtsam::Vector
4584 evaluateError (const gtsam::Pose3 &Ti, const gtsam::Pose3 &Tj,
4685 OptionalJacobian residual_D_Ti = boost::none,
4786 OptionalJacobian residual_D_Tj = boost::none) const noexcept ;
4887};
4988
89+ // / @brief Structure that holds point-point correspondences and computes their error
90+ // /
91+ // / Points are stored in a std::vector that is then mapped to Eigen matrices for
92+ // / efficient computation.
5093struct PointPoint {
94+ // / @brief Shared pointer type
5195 typedef std::shared_ptr<PointPoint> Ptr;
5296
97+ // / @brief Vectors to hold point data
5398 std::vector<double > p_i;
5499 std::vector<double > p_j;
55100
56101 PointPoint () = default ;
57102
58- size_t num_residuals () const noexcept { return p_i.size (); }
59- size_t num_constraints () const noexcept { return p_i.size () / 3 ; }
60-
103+ // / @brief Add a new point-point correspondence
61104 void push_back (const PointFeat &p_i_, const PointFeat &p_j_) {
62105 p_i.insert (p_i.end (), {p_i_.x , p_i_.y , p_i_.z });
63106 p_j.insert (p_j.end (), {p_j_.x , p_j_.y , p_j_.z });
64107 }
65108
109+ // / @brief Clear all stored correspondences
66110 void clear () noexcept {
67111 p_i.clear ();
68112 p_j.clear ();
69113 }
70114
115+ // / @brief Get the number of residuals (three per correspondence)
116+ size_t num_residuals () const noexcept { return p_i.size (); }
117+
118+ // / @brief Get the number of constraints / correspondences
119+ size_t num_constraints () const noexcept { return p_i.size () / 3 ; }
120+
121+ // / @brief Evaluate the residual given two poses
122+ // /
123+ // / @param Ti The pose of the first frame
124+ // / @param Tj The pose of the second frame
125+ // / @param residual_D_Ti Optional Jacobian of the residual w.r.t. Ti
126+ // / @param residual_D_Tj Optional Jacobian of the residual w.r.t. Tj
127+ // / @return The residual vector
71128 [[nodiscard]] gtsam::Vector
72129 evaluateError (const gtsam::Pose3 &Ti, const gtsam::Pose3 &Tj,
73130 OptionalJacobian residual_D_Ti = boost::none,
74131 OptionalJacobian residual_D_Tj = boost::none) const noexcept ;
75132};
76133
134+ // / @brief A wrapper factor that holds both plane-point and point-point constraints
77135class FeatureFactor : public DenseFactor {
78136public:
79- PlanePoint::Ptr plane_plane;
137+ // / @brief Plane-point constraints
138+ PlanePoint::Ptr plane_point;
139+
140+ // / @brief Point-point constraints
80141 PointPoint::Ptr point_point;
81142
82143public:
144+ // / @brief Constructor
145+ // /
146+ // / @param i Key for the first pose
147+ // / @param j Key for the second pose
148+ // / @param constraint A tuple containing plane-point and point-point constraints
149+ // / @param sigma The isotropic noise standard deviation
83150 FeatureFactor (const gtsam::Key i, const gtsam::Key j,
84151 const std::tuple<PlanePoint::Ptr, PointPoint::Ptr> &constraint,
85152 double sigma) noexcept ;
86153
154+ // / @brief Evaluate the residual given two poses
155+ // /
156+ // / @param Ti The pose of the first frame
157+ // / @param Tj The pose of the second frame
158+ // / @param residual_D_Ti Optional Jacobian of the residual w.r.t. Ti
159+ // / @param residual_D_Tj Optional Jacobian of the residual w.r.t. Tj
160+ // / @return The residual vector
87161 [[nodiscard]] gtsam::Vector
88162 evaluateError (const gtsam::Pose3 &Ti, const gtsam::Pose3 &Tj,
89163 boost::optional<gtsam::Matrix &> residual_D_Ti = boost::none,
90164 boost::optional<gtsam::Matrix &> residual_D_Tj =
91165 boost::none) const noexcept override ;
92-
93- [[nodiscard]] gtsam::Key getKey_i () const noexcept { return keys_[0 ]; }
94-
95- [[nodiscard]] gtsam::Key getKey_j () const noexcept { return keys_[1 ]; }
96166};
97167
98168} // namespace form
0 commit comments