19 #ifndef GRAPH_FACTORS_POINT_TO_HANDRAIL_ENDPOINT_FACTOR_H_ 
   20 #define GRAPH_FACTORS_POINT_TO_HANDRAIL_ENDPOINT_FACTOR_H_ 
   22 #include <gtsam/geometry/Pose3.h> 
   23 #include <gtsam/geometry/Point3.h> 
   24 #include <gtsam/nonlinear/NonlinearFactor.h> 
   30   typedef NoiseModelFactor1<Pose3> Base;
 
   38                                 const SharedNoiseModel& model, Key pose_key)
 
   39       : Base(model, pose_key),
 
   45   void print(
const std::string& s = 
"", 
const KeyFormatter& keyFormatter = DefaultKeyFormatter)
 const override {
 
   46     std::cout << s << 
"PointToHandrailEndpointFactor, z = ";
 
   51     Base::print(
"", keyFormatter);
 
   54   bool equals(
const NonlinearFactor& p, 
double tol = 1e-9)
 const override {
 
   55     const This* e = 
dynamic_cast<const This*
>(&p);
 
   62   Vector 
evaluateError(
const Pose3& world_T_body, boost::optional<Matrix&> H = boost::none)
 const override {
 
   64       Matrix66 d_world_T_sensor_d_world_T_body;
 
   65       Matrix36 d_world_t_point_d_world_T_sensor;
 
   66       Matrix33 d_local_d_world_t_point;
 
   67       const auto error = 
getError(world_T_body, d_world_T_sensor_d_world_T_body, d_world_t_point_d_world_T_sensor,
 
   68                                   d_local_d_world_t_point);
 
   69       *H = d_local_d_world_t_point * d_world_t_point_d_world_T_sensor * d_world_T_sensor_d_world_T_body;
 
   75   Vector 
getError(
const Pose3& world_T_body, OptionalJacobian<6, 6> d_world_T_sensor_d_world_T_body = boost::none,
 
   76                   OptionalJacobian<3, 6> d_world_t_point_d_world_T_sensor = boost::none,
 
   77                   OptionalJacobian<3, 3> d_local_d_world_t_point = boost::none)
 const {
 
   78     const Pose3 world_T_sensor = world_T_body.transformPoseFrom(body_T_sensor_, d_world_T_sensor_d_world_T_body);
 
   79     const Point3 world_t_point = world_T_sensor.transformFrom(sensor_t_point_, d_world_t_point_d_world_T_sensor);
 
   80     const double distance_to_endpoint_a = (world_t_point - world_t_endpoint_a_).norm();
 
   81     const double distance_to_endpoint_b = (world_t_point - world_t_endpoint_b_).norm();
 
   83     const Point3& world_t_closest_endpoint =
 
   84       distance_to_endpoint_a < distance_to_endpoint_b ? world_t_endpoint_a_ : world_t_endpoint_b_;
 
   85     const Point3 world_F_point_t_closest_endpoint =
 
   86       local(world_t_point, world_t_closest_endpoint, d_local_d_world_t_point);
 
   87     return world_F_point_t_closest_endpoint;
 
   92   static Point3 
local(
const Point3& point1, 
const Point3& point2,
 
   93                       OptionalJacobian<3, 3> d_local_d_point1 = boost::none) {
 
   94     if (d_local_d_point1) {
 
   95       *d_local_d_point1 = I_3x3;
 
   97     return point1 - point2;
 
  107   template <
class ARCHIVE>
 
  108   void serialize(ARCHIVE& ar, 
const unsigned int ) {
 
  109     ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
 
  110     ar& BOOST_SERIALIZATION_NVP(sensor_t_point_);
 
  111     ar& BOOST_SERIALIZATION_NVP(world_t_endpoint_a_);
 
  112     ar& BOOST_SERIALIZATION_NVP(world_t_endpoint_b_);
 
  113     ar& BOOST_SERIALIZATION_NVP(body_T_sensor_);
 
  116   Point3 sensor_t_point_;
 
  117   Point3 world_t_endpoint_a_;
 
  118   Point3 world_t_endpoint_b_;
 
  119   Pose3 body_T_sensor_;
 
  122   GTSAM_MAKE_ALIGNED_OPERATOR_NEW
 
  126 #endif  // GRAPH_FACTORS_POINT_TO_HANDRAIL_ENDPOINT_FACTOR_H_