Split up circle intersection code into three routines that are used in SmartRangeFactor
							parent
							
								
									140e8a8c7a
								
							
						
					
					
						commit
						d041c5b8a8
					
				|  | @ -68,59 +68,54 @@ double Point2::distance(const Point2& point, boost::optional<Matrix&> H1, | ||||||
|     return d.norm(); |     return d.norm(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Calculate f and h, respectively the parallel and perpendicular distance of | ||||||
|  |  * the intersections of two circles along and from the line connecting the centers. | ||||||
|  |  * Both are dimensionless fractions of the distance d between the circle centers. | ||||||
|  |  * If the circles do not intersect or they are identical, returns boost::none. | ||||||
|  |  * If one solution (touching circles, as determined by tol), h will be exactly zero. | ||||||
|  |  * h is a good measure for how accurate the intersection will be, as when circles touch | ||||||
|  |  * or nearly touch, the intersection is ill-defined with noisy radius measurements. | ||||||
|  |  * @param R_d : R/d, ratio of radius of first circle to distance between centers | ||||||
|  |  * @param r_d : r/d, ratio of radius of second circle to distance between centers | ||||||
|  |  * @param tol: absolute tolerance below which we consider touching circles | ||||||
|  |  */ | ||||||
| /* ************************************************************************* */ | /* ************************************************************************* */ | ||||||
| // Calculate h, the distance of the intersections of two circles from the center line.
 |  | ||||||
| // This is a dimensionless fraction of the distance d between the circle centers,
 |  | ||||||
| // and also determines how "good" the intersection is. If the circles do not intersect
 |  | ||||||
| // or they are identical, returns boost::none. If one solution, h -> 0.
 |  | ||||||
| // @param R_d : R/d, ratio of radius of first circle to distance between centers
 |  | ||||||
| // @param r_d : r/d, ratio of radius of second circle to distance between centers
 |  | ||||||
| // @param tol: absolute tolerance below which we consider touching circles
 |  | ||||||
| // Math inspired by http://paulbourke.net/geometry/circlesphere/
 | // Math inspired by http://paulbourke.net/geometry/circlesphere/
 | ||||||
| static boost::optional<double> circleCircleQuality(double R_d, double r_d, double tol=1e-9) { | boost::optional<Point2> Point2::CircleCircleIntersection(double R_d, double r_d, | ||||||
|  |     double tol) { | ||||||
| 
 | 
 | ||||||
|   double R2_d2 = R_d*R_d; // Yes, RD-D2 !
 |   double R2_d2 = R_d*R_d; // Yes, RD-D2 !
 | ||||||
|   double f = 0.5 + 0.5*(R2_d2 - r_d*r_d); |   double f = 0.5 + 0.5*(R2_d2 - r_d*r_d); | ||||||
|   double h2 = R2_d2 - f*f; |   double h2 = R2_d2 - f*f; // just right triangle rule
 | ||||||
| 
 | 
 | ||||||
|   // h^2<0 is equivalent to (d > (R + r) || d < (R - r))
 |   // h^2<0 is equivalent to (d > (R + r) || d < (R - r))
 | ||||||
|   // Hence, there are only solutions if >=0
 |   // Hence, there are only solutions if >=0
 | ||||||
|   if (h2<-tol) return boost::none; // allow *slightly* negative
 |   if (h2<-tol) return boost::none; // allow *slightly* negative
 | ||||||
|   else if (h2<tol) return 0.0; // one solution
 |   else if (h2<tol) return Point2(f,0.0); // one solution
 | ||||||
|   else return sqrt(h2); // two solutions
 |   else return Point2(f,sqrt(h2)); // two solutions
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ************************************************************************* */ | /* ************************************************************************* */ | ||||||
| // Math inspired by http://paulbourke.net/geometry/circlesphere/
 | list<Point2> Point2::CircleCircleIntersection(Point2 c1, Point2 c2, | ||||||
| list<Point2> Point2::CircleCircleIntersection(double R, Point2 c, double r) { |     boost::optional<Point2> fh) { | ||||||
| 
 | 
 | ||||||
|   list<Point2> solutions; |   list<Point2> solutions; | ||||||
|  |   // If fh==boost::none, there are no solutions, i.e., d > (R + r) || d < (R - r)
 | ||||||
|  |   if (fh) { | ||||||
|  |     // vector between circle centers
 | ||||||
|  |     Point2 c12 = c2-c1; | ||||||
| 
 | 
 | ||||||
|   // distance between circle centers.
 |  | ||||||
|   double d2 = c.x() * c.x() + c.y() * c.y(), d = sqrt(d2); |  | ||||||
| 
 |  | ||||||
|   // circles coincide, either no solution or infinite number of solutions.
 |  | ||||||
|   if (d2<1e-9) return solutions; |  | ||||||
| 
 |  | ||||||
|   // Calculate h, the distance of the intersections from the center line,
 |  | ||||||
|   // as a dimensionless fraction of  the distance d.
 |  | ||||||
|   // It is the solution of a quadratic, so it has either 2 solutions, is 0, or none
 |  | ||||||
|   double _d = 1.0/d, R_d = R*_d, r_d=r*_d; |  | ||||||
|   boost::optional<double> h = circleCircleQuality(R_d,r_d); |  | ||||||
| 
 |  | ||||||
|   // If h== boost::none, there are no solutions, i.e., d > (R + r) || d < (R - r)
 |  | ||||||
|   if (h) { |  | ||||||
|     // Determine p2, the point where the line through the circle
 |     // Determine p2, the point where the line through the circle
 | ||||||
|     // intersection points crosses the line between the circle centers.
 |     // intersection points crosses the line between the circle centers.
 | ||||||
|     double f = 0.5 + 0.5*(R_d*R_d - r_d*r_d); |     Point2 p2 = c1 + fh->x() * c12; | ||||||
|     Point2 p2 = f * c; |  | ||||||
| 
 | 
 | ||||||
|     // If h == 0, the circles are touching, so just return one point
 |     // If h == 0, the circles are touching, so just return one point
 | ||||||
|     if (h==0.0) |     if (fh->y()==0.0) | ||||||
|       solutions.push_back(p2); |       solutions.push_back(p2); | ||||||
|     else { |     else { | ||||||
|       // determine the offsets of the intersection points from p
 |       // determine the offsets of the intersection points from p
 | ||||||
|       Point2 offset = (*h) * Point2(-c.y(), c.x()); |       Point2 offset = fh->y() * Point2(-c12.y(), c12.x()); | ||||||
| 
 | 
 | ||||||
|       // Determine the absolute intersection points.
 |       // Determine the absolute intersection points.
 | ||||||
|       solutions.push_back(p2 + offset); |       solutions.push_back(p2 + offset); | ||||||
|  | @ -130,56 +125,22 @@ list<Point2> Point2::CircleCircleIntersection(double R, Point2 c, double r) { | ||||||
|   return solutions; |   return solutions; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //list<Point2> Point2::CircleCircleIntersection(double R, Point2 c, double r) {
 |  | ||||||
| //
 |  | ||||||
| //  list<Point2> solutions;
 |  | ||||||
| //
 |  | ||||||
| //  // Math inspired by http://paulbourke.net/geometry/circlesphere/
 |  | ||||||
| //  // Changed to avoid sqrt in case there are 0 or 1 intersections, and only one div
 |  | ||||||
| //
 |  | ||||||
| //  // squared distance between circle centers.
 |  | ||||||
| //  double d2 = c.x() * c.x() + c.y() * c.y();
 |  | ||||||
| //
 |  | ||||||
| //  // A crucial quantity we compute is h, a the distance of the intersections
 |  | ||||||
| //  // from the center line, as a dimensionless fraction of  the distance d.
 |  | ||||||
| //  // It is the solution of a quadratic, so it has either 2 solutions, is 0, or none
 |  | ||||||
| //  // We calculate it as sqrt(h^2*d^4)/d^2, but first check whether h^2*d^4>=0
 |  | ||||||
| //  double R2 = R*R;
 |  | ||||||
| //  double R2d2 = R2*d2; // yes, R2-D2!
 |  | ||||||
| //  double b = R2 + d2 - r*r;
 |  | ||||||
| //  double b2 = b*b;
 |  | ||||||
| //  double h2d4 = R2d2 - 0.25*b2; // h^2*d^4
 |  | ||||||
| //
 |  | ||||||
| //  // h^2*d^4<0 is equivalent to (d > (R + r) || d < (R - r))
 |  | ||||||
| //  // Hence, there are only solutions if >=0
 |  | ||||||
| //  if (h2d4>=0) {
 |  | ||||||
| //    // Determine p2, the point where the line through the circle
 |  | ||||||
| //    // intersection points crosses the line between the circle centers.
 |  | ||||||
| //    double i2 = 1.0/d2;
 |  | ||||||
| //    double f = 0.5*b*i2;
 |  | ||||||
| //    Point2 p2 = f * c;
 |  | ||||||
| //
 |  | ||||||
| //    // If h^2*d^4 == 0, the circles are touching, so just return one point
 |  | ||||||
| //    if (h2d4 < 1e-9)
 |  | ||||||
| //      solutions.push_back(p2);
 |  | ||||||
| //    else {
 |  | ||||||
| //      // determine the offsets of the intersection points from p
 |  | ||||||
| //      double h = sqrt(h2d4)*i2; // h = sqrt(h^2*d^4)/d^2
 |  | ||||||
| //      Point2 offset = h * Point2(-c.y(), c.x());
 |  | ||||||
| //
 |  | ||||||
| //      // Determine the absolute intersection points.
 |  | ||||||
| //      solutions.push_back(p2 + offset);
 |  | ||||||
| //      solutions.push_back(p2 - offset);
 |  | ||||||
| //    }
 |  | ||||||
| //  }
 |  | ||||||
| //  return solutions;
 |  | ||||||
| //}
 |  | ||||||
| //
 |  | ||||||
| /* ************************************************************************* */ | /* ************************************************************************* */ | ||||||
| list<Point2> Point2::CircleCircleIntersection(Point2 c1, double r1, Point2 c2, double r2) { | list<Point2> Point2::CircleCircleIntersection(Point2 c1, double r1, Point2 c2, | ||||||
|   list<Point2> solutions = Point2::CircleCircleIntersection(r1,c2-c1,r2); |     double r2, double tol) { | ||||||
|   BOOST_FOREACH(Point2& p, solutions) p+= c1; | 
 | ||||||
|   return solutions; |   // distance between circle centers.
 | ||||||
|  |   double d = c1.dist(c2); | ||||||
|  | 
 | ||||||
|  |   // centers coincide, either no solution or infinite number of solutions.
 | ||||||
|  |   if (d<1e-9) return list<Point2>(); | ||||||
|  | 
 | ||||||
|  |   // Calculate f and h given normalized radii
 | ||||||
|  |   double _d = 1.0/d, R_d = r1*_d, r_d=r2*_d; | ||||||
|  |   boost::optional<Point2> fh = CircleCircleIntersection(R_d,r_d); | ||||||
|  | 
 | ||||||
|  |   // Call version that takes fh
 | ||||||
|  |   return CircleCircleIntersection(c1, c2, fh); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ************************************************************************* */ | /* ************************************************************************* */ | ||||||
|  |  | ||||||
|  | @ -65,14 +65,30 @@ public: | ||||||
|     y_ = v(1); |     y_ = v(1); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /**
 |   /*
 | ||||||
|    * @brief Intersect Circle with radius R at origin, with circle of radius r at c |    * @brief Circle-circle intersection, given normalized radii. | ||||||
|    * @param R radius of circle at origin |    * Calculate f and h, respectively the parallel and perpendicular distance of | ||||||
|    * @param center center of second circle |    * the intersections of two circles along and from the line connecting the centers. | ||||||
|    * @param r radius of second circle |    * Both are dimensionless fractions of the distance d between the circle centers. | ||||||
|    * @return list of solutions (0,1, or 2 points) |    * If the circles do not intersect or they are identical, returns boost::none. | ||||||
|  |    * If one solution (touching circles, as determined by tol), h will be exactly zero. | ||||||
|  |    * h is a good measure for how accurate the intersection will be, as when circles touch | ||||||
|  |    * or nearly touch, the intersection is ill-defined with noisy radius measurements. | ||||||
|  |    * @param R_d : R/d, ratio of radius of first circle to distance between centers | ||||||
|  |    * @param r_d : r/d, ratio of radius of second circle to distance between centers | ||||||
|  |    * @param tol: absolute tolerance below which we consider touching circles | ||||||
|  |    * @return optional Point2 with f and h, boost::none if no solution. | ||||||
|    */ |    */ | ||||||
|   static std::list<Point2> CircleCircleIntersection(double R, Point2 c, double r); |   static boost::optional<Point2> CircleCircleIntersection(double R_d, double r_d, | ||||||
|  |       double tol = 1e-9); | ||||||
|  | 
 | ||||||
|  |   /*
 | ||||||
|  |    * @brief Circle-circle intersection, from the normalized radii solution. | ||||||
|  |    * @param c1 center of first circle | ||||||
|  |    * @param c2 center of second circle | ||||||
|  |    * @return list of solutions (0,1, or 2). Identical circles will return empty list, as well. | ||||||
|  |    */ | ||||||
|  |   static std::list<Point2> CircleCircleIntersection(Point2 c1, Point2 c2, boost::optional<Point2>); | ||||||
| 
 | 
 | ||||||
|   /**
 |   /**
 | ||||||
|    * @brief Intersect 2 circles |    * @brief Intersect 2 circles | ||||||
|  | @ -80,8 +96,11 @@ public: | ||||||
|    * @param r1 radius of first circle |    * @param r1 radius of first circle | ||||||
|    * @param c2 center of second circle |    * @param c2 center of second circle | ||||||
|    * @param r2 radius of second circle |    * @param r2 radius of second circle | ||||||
|  |    * @param tol: absolute tolerance below which we consider touching circles | ||||||
|  |    * @return list of solutions (0,1, or 2). Identical circles will return empty list, as well. | ||||||
|    */ |    */ | ||||||
|   static std::list<Point2> CircleCircleIntersection(Point2 c1, double r1, Point2 c2, double r2); |   static std::list<Point2> CircleCircleIntersection(Point2 c1, double r1, | ||||||
|  |       Point2 c2, double r2, double tol = 1e-9); | ||||||
| 
 | 
 | ||||||
|   /// @}
 |   /// @}
 | ||||||
|   /// @name Testable
 |   /// @name Testable
 | ||||||
|  |  | ||||||
|  | @ -148,30 +148,30 @@ TEST( Point2, circleCircleIntersection) { | ||||||
|   double offset = 0.994987; |   double offset = 0.994987; | ||||||
|   // Test intersections of circle moving from inside to outside
 |   // Test intersections of circle moving from inside to outside
 | ||||||
| 
 | 
 | ||||||
|   list<Point2> inside = Point2::CircleCircleIntersection(5,Point2(0,0),1); |   list<Point2> inside = Point2::CircleCircleIntersection(Point2(0,0),5,Point2(0,0),1); | ||||||
|   EXPECT_LONGS_EQUAL(0,inside.size()); |   EXPECT_LONGS_EQUAL(0,inside.size()); | ||||||
| 
 | 
 | ||||||
|   list<Point2> touching1 = Point2::CircleCircleIntersection(5,Point2(4,0),1); |   list<Point2> touching1 = Point2::CircleCircleIntersection(Point2(0,0),5,Point2(4,0),1); | ||||||
|   EXPECT_LONGS_EQUAL(1,touching1.size()); |   EXPECT_LONGS_EQUAL(1,touching1.size()); | ||||||
|   EXPECT(assert_equal(Point2(5,0), touching1.front())); |   EXPECT(assert_equal(Point2(5,0), touching1.front())); | ||||||
| 
 | 
 | ||||||
|   list<Point2> common = Point2::CircleCircleIntersection(5,Point2(5,0),1); |   list<Point2> common = Point2::CircleCircleIntersection(Point2(0,0),5,Point2(5,0),1); | ||||||
|   EXPECT_LONGS_EQUAL(2,common.size()); |   EXPECT_LONGS_EQUAL(2,common.size()); | ||||||
|   EXPECT(assert_equal(Point2(4.9,  offset), common.front(), 1e-6)); |   EXPECT(assert_equal(Point2(4.9,  offset), common.front(), 1e-6)); | ||||||
|   EXPECT(assert_equal(Point2(4.9, -offset), common.back(), 1e-6)); |   EXPECT(assert_equal(Point2(4.9, -offset), common.back(), 1e-6)); | ||||||
| 
 | 
 | ||||||
|   list<Point2> touching2 = Point2::CircleCircleIntersection(5,Point2(6,0),1); |   list<Point2> touching2 = Point2::CircleCircleIntersection(Point2(0,0),5,Point2(6,0),1); | ||||||
|   EXPECT_LONGS_EQUAL(1,touching2.size()); |   EXPECT_LONGS_EQUAL(1,touching2.size()); | ||||||
|   EXPECT(assert_equal(Point2(5,0), touching2.front())); |   EXPECT(assert_equal(Point2(5,0), touching2.front())); | ||||||
| 
 | 
 | ||||||
|   // test rotated case
 |   // test rotated case
 | ||||||
|   list<Point2> rotated = Point2::CircleCircleIntersection(5,Point2(0,5),1); |   list<Point2> rotated = Point2::CircleCircleIntersection(Point2(0,0),5,Point2(0,5),1); | ||||||
|   EXPECT_LONGS_EQUAL(2,rotated.size()); |   EXPECT_LONGS_EQUAL(2,rotated.size()); | ||||||
|   EXPECT(assert_equal(Point2(-offset, 4.9), rotated.front(), 1e-6)); |   EXPECT(assert_equal(Point2(-offset, 4.9), rotated.front(), 1e-6)); | ||||||
|   EXPECT(assert_equal(Point2( offset, 4.9), rotated.back(), 1e-6)); |   EXPECT(assert_equal(Point2( offset, 4.9), rotated.back(), 1e-6)); | ||||||
| 
 | 
 | ||||||
|   // test r1<r2
 |   // test r1<r2
 | ||||||
|   list<Point2> smaller = Point2::CircleCircleIntersection(1,Point2(5,0),5); |   list<Point2> smaller = Point2::CircleCircleIntersection(Point2(0,0),1,Point2(5,0),5); | ||||||
|   EXPECT_LONGS_EQUAL(2,smaller.size()); |   EXPECT_LONGS_EQUAL(2,smaller.size()); | ||||||
|   EXPECT(assert_equal(Point2(0.1,  offset), smaller.front(), 1e-6)); |   EXPECT(assert_equal(Point2(0.1,  offset), smaller.front(), 1e-6)); | ||||||
|   EXPECT(assert_equal(Point2(0.1, -offset), smaller.back(), 1e-6)); |   EXPECT(assert_equal(Point2(0.1, -offset), smaller.back(), 1e-6)); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,136 @@ | ||||||
|  | /**
 | ||||||
|  |  * @file SmartRangeFactor.h | ||||||
|  |  * | ||||||
|  |  * @brief A smart factor for range-only SLAM that does initialization and marginalization | ||||||
|  |  *  | ||||||
|  |  * @date Sep 10, 2012 | ||||||
|  |  * @author Alex Cunningham | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gtsam_unstable/base/dllexport.h> | ||||||
|  | #include <gtsam/nonlinear/NonlinearFactor.h> | ||||||
|  | #include <gtsam/nonlinear/Key.h> | ||||||
|  | #include <gtsam/geometry/Pose2.h> | ||||||
|  | #include <boost/foreach.hpp> | ||||||
|  | #include <map> | ||||||
|  | 
 | ||||||
|  | namespace gtsam { | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Smart factor for range SLAM | ||||||
|  |  * @addtogroup SLAM | ||||||
|  |  */ | ||||||
|  | class GTSAM_UNSTABLE_EXPORT SmartRangeFactor: public NoiseModelFactor { | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  |   struct KeyedRange { | ||||||
|  |     KeyedRange(Key k, double r) : | ||||||
|  |         key(k), range(r) { | ||||||
|  |     } | ||||||
|  |     Key key; | ||||||
|  |     double range; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   struct Circle2 { | ||||||
|  |     Circle2(const Point2& p, double r) : | ||||||
|  |         center(p), radius(r) { | ||||||
|  |     } | ||||||
|  |     Point2 center; | ||||||
|  |     double radius; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   /// Range measurements
 | ||||||
|  |   std::list<KeyedRange> measurements_; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |   /** Default constructor: don't use directly */ | ||||||
|  |   SmartRangeFactor() { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** standard binary constructor */ | ||||||
|  |   SmartRangeFactor(const SharedNoiseModel& model) { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   virtual ~SmartRangeFactor() { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Add a range measurement to a pose with given key.
 | ||||||
|  |   void addRange(Key key, double measuredRange) { | ||||||
|  |     measurements_.push_back(KeyedRange(key, measuredRange)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Number of measurements added
 | ||||||
|  |   size_t nrMeasurements() const { | ||||||
|  |     return measurements_.size(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // testable
 | ||||||
|  | 
 | ||||||
|  |   /** print */ | ||||||
|  |   virtual void print(const std::string& s = "", | ||||||
|  |       const KeyFormatter& keyFormatter = DefaultKeyFormatter) const { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Check if two factors are equal */ | ||||||
|  |   virtual bool equals(const NonlinearFactor& f, double tol = 1e-9) const { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // factor interface
 | ||||||
|  | 
 | ||||||
|  |   /**
 | ||||||
|  |    * Triangulate a point from at least three pose-range pairs | ||||||
|  |    * Checks for best pair that includes first point | ||||||
|  |    */ | ||||||
|  |   static Point2 triangulate( | ||||||
|  |       const std::list<Circle2>& circles) { | ||||||
|  |     Circle2 circle1 = circles.front(); | ||||||
|  |     boost::optional<Point2> best_fh; | ||||||
|  |     boost::optional<Circle2> best_circle; | ||||||
|  |     BOOST_FOREACH(const Circle2& it, circles) { | ||||||
|  |       // distance between circle centers.
 | ||||||
|  |       double d = circle1.center.dist(it.center); | ||||||
|  |       if (d<1e-9) continue; | ||||||
|  |       boost::optional<Point2> fh = Point2::CircleCircleIntersection(circle1.radius/d,it.radius/d); | ||||||
|  |       if (fh && (!best_fh || fh->y()>best_fh->y())) { | ||||||
|  |         best_fh = fh; | ||||||
|  |         best_circle = it; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     std::list<Point2> solutions = Point2::CircleCircleIntersection( | ||||||
|  |         circle1.center, best_circle->center, best_fh); | ||||||
|  |     solutions.front().print("front"); | ||||||
|  |     solutions.back().print("back"); | ||||||
|  |     return solutions.front(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /**
 | ||||||
|  |    * Error function *without* the NoiseModel, \f$ z-h(x) \f$. | ||||||
|  |    */ | ||||||
|  |   virtual Vector unwhitenedError(const Values& x, | ||||||
|  |       boost::optional<std::vector<Matrix>&> H = boost::none) const { | ||||||
|  |     size_t K = nrMeasurements(); | ||||||
|  |     Vector errors = zero(K); | ||||||
|  |     if (K >= 3) { | ||||||
|  |       std::list<Circle2> circles; | ||||||
|  |       BOOST_FOREACH(const KeyedRange& it, measurements_) { | ||||||
|  |         const Pose2& pose = x.at<Pose2>(it.key); | ||||||
|  |         circles.push_back( | ||||||
|  |             Circle2(pose.translation(), it.range)); | ||||||
|  |       } | ||||||
|  |       Point2 optimizedPoint = triangulate(circles); | ||||||
|  |       size_t i = 0; | ||||||
|  |       BOOST_FOREACH(const Circle2& it, circles) { | ||||||
|  |         errors[i++] = it.radius - it.center.distance(optimizedPoint); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return errors; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // \namespace gtsam
 | ||||||
|  | 
 | ||||||
|  | @ -0,0 +1,83 @@ | ||||||
|  | /* ----------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |  * GTSAM Copyright 2010, Georgia Tech Research Corporation,  | ||||||
|  |  * Atlanta, Georgia 30332-0415 | ||||||
|  |  * All Rights Reserved | ||||||
|  |  * Authors: Frank Dellaert, et al. (see THANKS for the full author list) | ||||||
|  | 
 | ||||||
|  |  * See LICENSE for the license information | ||||||
|  | 
 | ||||||
|  |  * -------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  *  @file  testSmartRangeFactor.cpp | ||||||
|  |  *  @brief Unit tests for SmartRangeFactor Class | ||||||
|  |  *  @author Frank Dellaert | ||||||
|  |  *  @date Nov 2013 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <gtsam_unstable/slam/SmartRangeFactor.h> | ||||||
|  | #include <CppUnitLite/TestHarness.h> | ||||||
|  | 
 | ||||||
|  | using namespace std; | ||||||
|  | using namespace gtsam; | ||||||
|  | 
 | ||||||
|  | const noiseModel::Base::shared_ptr gaussian = noiseModel::Isotropic::Sigma(1, | ||||||
|  |     2.0); | ||||||
|  | 
 | ||||||
|  | /* ************************************************************************* */ | ||||||
|  | 
 | ||||||
|  | TEST( SmartRangeFactor, constructor ) { | ||||||
|  |   SmartRangeFactor f1; | ||||||
|  |   LONGS_EQUAL(0, f1.nrMeasurements()) | ||||||
|  |   SmartRangeFactor f2(gaussian); | ||||||
|  |   LONGS_EQUAL(0, f2.nrMeasurements()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ************************************************************************* */ | ||||||
|  | 
 | ||||||
|  | TEST( SmartRangeFactor, addRange ) { | ||||||
|  |   SmartRangeFactor f(gaussian); | ||||||
|  |   f.addRange(1, 10); | ||||||
|  |   f.addRange(1, 12); | ||||||
|  |   LONGS_EQUAL(2, f.nrMeasurements()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ************************************************************************* */ | ||||||
|  | 
 | ||||||
|  | TEST( SmartRangeFactor, unwhitenedError ) { | ||||||
|  |   // Test situation:
 | ||||||
|  |   Point2 p(0, 10); | ||||||
|  |   Pose2 pose1(0, 0, 0), pose2(5, 0, 0), pose3(5, 5, 0); | ||||||
|  |   double r1 = pose1.range(p), r2 = pose2.range(p), r3 = pose3.range(p); | ||||||
|  |   DOUBLES_EQUAL(10, r1, 1e-9); | ||||||
|  |   DOUBLES_EQUAL(sqrt(100+25), r2, 1e-9); | ||||||
|  |   DOUBLES_EQUAL(sqrt(50), r3, 1e-9); | ||||||
|  | 
 | ||||||
|  |   Values values; // all correct
 | ||||||
|  |   values.insert(1, pose1); | ||||||
|  |   values.insert(2, pose2); | ||||||
|  |   values.insert(3, pose3); | ||||||
|  | 
 | ||||||
|  |   SmartRangeFactor f(gaussian); | ||||||
|  |   f.addRange(1, r1); | ||||||
|  | 
 | ||||||
|  |   // Whenever there are two ranges or less, error should be zero
 | ||||||
|  |   Vector actual1 = f.unwhitenedError(values); | ||||||
|  |   EXPECT(assert_equal(Vector_(1,0.0), actual1)); | ||||||
|  |   f.addRange(2, r2); | ||||||
|  |   Vector actual2 = f.unwhitenedError(values); | ||||||
|  |   EXPECT(assert_equal(Vector2(0,0), actual2)); | ||||||
|  | 
 | ||||||
|  |   f.addRange(3, r3); | ||||||
|  |   Vector actual3 = f.unwhitenedError(values); | ||||||
|  |   EXPECT(assert_equal(Vector3(0,0,0), actual3)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ************************************************************************* */ | ||||||
|  | int main() { | ||||||
|  |   TestResult tr; | ||||||
|  |   return TestRegistry::runAllTests(tr); | ||||||
|  | } | ||||||
|  | /* ************************************************************************* */ | ||||||
|  | 
 | ||||||
		Loading…
	
		Reference in New Issue