#include <gtsam/slam/PriorFactor.h>
#include <gtsam/nonlinear/NonlinearFactorGraph.h>
#include <gtsam/nonlinear/Values.h>
#include <gtsam/nonlinear/GaussNewtonOptimizer.h>
#include <gtsam/geometry/OrientedPlane3.h>
#include <gtsam/geometry/Pose3.h>
#include <gtsam/inference/Symbol.h>
#include <boost/optional.hpp>
#include <iostream>
using namespace gtsam;
class CustomOrientedPlane3Factor : public NoiseModelFactor1<Pose3> {
OrientedPlane3 measured_;
public:
CustomOrientedPlane3Factor(const OrientedPlane3& measured, const SharedNoiseModel& model, Key poseKey)
: NoiseModelFactor1<Pose3>(model, poseKey), measured_(measured) {}
Vector evaluateError(const Pose3& pose, boost::optional<Matrix&> H = boost::none) const override {
OrientedPlane3 transformedPlane = measured_.transform(pose, H);
double zError = pose.translation().z() - transformedPlane.planeCoefficients()(3);
Vector3 normalError = transformedPlane.planeCoefficients().head<3>() - measured_.planeCoefficients().head<3>();
Vector error(4);
error << normalError, zError;
if (H) {
*H = Matrix::Zero(4, 6);
(*H)(3, 5) = 1.0;
}
return error;
}
};
int main() {
NonlinearFactorGraph graph;
Pose3 initialPose(Rot3::Ypr(0.1, 0.1, 0.1), Point3(10.5, 20.4, 1.2));
Vector6 poseConstraint;
poseConstraint << 0.0, 0.0, 1.0, 1.0, 1.0, 1.0;
auto poseNoise = noiseModel::Diagonal::Sigmas(poseConstraint * 0.1);
graph.add(PriorFactor<Pose3>(Symbol('x', 0), initialPose, poseNoise));
std::cout << "Initial Pose:\n" << initialPose << std::endl;
std::vector<OrientedPlane3> observedPlanes = {
OrientedPlane3(0, 0, 1, -1.5),
OrientedPlane3(0, 0, 1, -2.0),
OrientedPlane3(0, 0, 1, -1.0),
OrientedPlane3(0, 0, 1, -0.5)
};
auto planeNoise = noiseModel::Isotropic::Sigma(4, 1e-3);
for (size_t i = 0; i < observedPlanes.size(); ++i) {
graph.add(boost::make_shared<CustomOrientedPlane3Factor>(observedPlanes[i], planeNoise, Symbol('x', 0)));
}
Values initialEstimate;
initialEstimate.insert(Symbol('x', 0), initialPose);
GaussNewtonParams params;
params.setMaxIterations(10);
params.setRelativeErrorTol(1e-5);
GaussNewtonOptimizer optimizer(graph, initialEstimate, params);
Values result = optimizer.optimize();
std::cout << "Optimized Pose:\n" << result.at<Pose3>(Symbol('x', 0)) << std::endl;
return 0;
}