Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

sonar_obs.hpp

Go to the documentation of this file.
00001 #ifndef _SONAR_OBS_HPP
00002 #define _SONAR_OBS_HPP
00003 
00004 #include <iostream>
00005 #include "properties.hpp"
00006 #include "coloring.hpp"
00007 #include "query_point.hpp"
00008 #include "arak.hpp"
00009 #include "grid.hpp"
00010 
00011 namespace Arak {
00012 
00017   struct SonarImpact {
00018     
00026     double proj_angle;
00027     
00032     double min_range;
00033     
00039     double visible_angle;
00040     
00044     Geometry::Direction dmin;
00045     
00049     Geometry::Direction dmax;
00050 
00056     Geometry::Point pmin;
00057     
00063     Geometry::Point pmax;
00064     
00069     Geometry::Point projection;
00070 
00074     SonarImpact() : proj_angle(0.0), 
00075         min_range(0.0), 
00076         visible_angle(0.0),
00077         pmin(CGAL::ORIGIN), 
00078         pmax(CGAL::ORIGIN),
00079         projection(CGAL::ORIGIN) { }
00080     
00092     SonarImpact(const Geometry::Point& source, 
00093     const Geometry::Direction& dmin,
00094     const Geometry::Direction& dmax,
00095     const Geometry::Point& pmin,
00096     const Geometry::Point& pmax) : 
00097       dmin(dmin), dmax(dmax), pmin(pmin), pmax(pmax) { 
00098       // Compute the point on the impact face closest to the source.
00099       Geometry::Line face_line(pmin, pmax);
00100       projection = face_line.projection(source);
00101       // Project the projection into the segment.
00102       if (CGAL::collinear_are_ordered_along_line(projection, pmin, pmax)) 
00103   projection = pmin;
00104       else if (CGAL::collinear_are_ordered_along_line(pmin, pmax, projection))
00105   projection = pmax;
00106       // Compute the impact information.
00107       Geometry::Direction fd = face_line.direction();
00108       Geometry::Direction psd = Geometry::Line(projection, source).direction();
00109       this->proj_angle = (atan2(CGAL::to_double(psd.dy()), 
00110         CGAL::to_double(psd.dx())) - 
00111         atan2(CGAL::to_double(fd.dy()), 
00112         CGAL::to_double(fd.dx())));
00113       this->min_range = 
00114   sqrt(CGAL::to_double(CGAL::squared_distance(source, projection)));
00115       if (dmin != dmax) {
00116   // Compute the visible angle.  First convert the directions to
00117   // angles.
00118   double amin = atan2(CGAL::to_double(dmin.dy()), 
00119           CGAL::to_double(dmin.dx()));
00120   double amax = atan2(CGAL::to_double(dmax.dy()), 
00121           CGAL::to_double(dmax.dx()));
00122   // Now compute the smaller of the two angles between them.
00123   double adiff1 = amax - amin;
00124   if (adiff1 < 0.0) adiff1 += 2 * M_PI;
00125   if (adiff1 >= 2 * M_PI) adiff1 -= 2 * M_PI;
00126   double adiff2 = amin - amax;
00127   if (adiff2 < 0.0) adiff2 += 2 * M_PI;
00128   if (adiff2 >= 2 * M_PI) adiff2 -= 2 * M_PI;
00129   this->visible_angle = std::min(fabs(adiff1), fabs(adiff2));
00130       } else
00131   this->visible_angle = 0.0;
00132     }
00133       
00143     SonarImpact(const Geometry::Point& source, 
00144     const Geometry::Point& pmin,
00145     const Geometry::Direction& dir,
00146     const Geometry::Point& corner,
00147     const Geometry::Point& pmax) : 
00148       dmin(dir), dmax(dir), pmin(corner), pmax(corner), projection(corner) { 
00149       this->proj_angle = 0.0; // ?
00150       this->min_range = 
00151   sqrt(CGAL::to_double(CGAL::squared_distance(source, corner)));
00152       this->visible_angle = 0.0;
00153     }
00154 
00159     bool isCorner() const { return (visible_angle == 0.0); }
00160 
00166     bool operator<(const SonarImpact& other) const {
00167       if (min_range < other.min_range)
00168   return true;
00169       else if (min_range == other.min_range) {
00170   return (isCorner() && !other.isCorner());
00171       } else
00172   return false;
00173     } 
00174   }; // End of class: SonarImpact
00175 
00191   void computeSonarImpacts(const Coloring& coloring,
00192          const Geometry::Point& vertex,
00193          const Geometry::Direction& min,
00194          const Geometry::Direction& max,
00195          const Geometry::Kernel::FT maxRange,
00196          std::vector<SonarImpact>& impacts,
00197          double* maxImpactRange = NULL);
00198 
00211   bool computeFirstSonarImpact(const Coloring& coloring,
00212              const Geometry::Point& vertex,
00213              const Geometry::Direction& min,
00214              const Geometry::Direction& max,
00215              const Geometry::Kernel::FT maxRange,
00216              SonarImpact& impact);
00217 
00222   class ArakPosteriorSonarObs : public ArakProcess, 
00223         public Coloring::Listener {
00224 
00225   protected:
00226 
00227     class SonarObs;
00228     typedef PointerHandle<SonarObs> SonarObsHandle;
00229 
00234     typedef Grid<SonarObsHandle> SonarObsIndex;
00235 
00239     class SonarObs : public QueryPointListener {
00240 
00241     public:
00242       
00246       Geometry::Point source;
00247 
00251       Geometry::Direction min;
00252 
00256       Geometry::Direction max;
00257 
00261       double range;
00262 
00266       Color sourceColor;
00267 
00271       double lp;
00272 
00277       Geometry::Triangle relevantRegion;
00278 
00282       typedef SonarObsIndex::Cell::Entry CellEntry;
00283 
00287       typedef std::list<CellEntry> CellEntryList;
00288 
00292       CellEntryList entries;
00293 
00298       CellEntryList unused;
00299 
00303       unsigned long int updateId;
00304 
00308       SonarObs(const Geometry::Point& source, 
00309          const double angle,
00310          const double range,
00311          const double aperture,
00312          const double maxRange);
00313 
00317       virtual ~SonarObs() {};
00318 
00324       virtual void recolor(Color color) {
00325   sourceColor = color;
00326       }
00327 
00328     }; // End of class: ArakPosteriorSonarObs::SonarObs
00329 
00333     const ArakProcess& prior;
00334 
00338     std::vector<SonarObs*> obs;
00339 
00343     SonarObsIndex* obsIndex;
00344 
00348     unsigned long int updateId;
00349 
00353     double aperture;
00354 
00359     double maxRange;
00360 
00365     double prob_max_range;
00366 
00370     double unif_outlier_weight;
00371 
00375     double exp_outlier_coef;
00376 
00381     double face_const_coef;
00382 
00387     double face_proj_angle_coef;
00388 
00393     double face_min_range_coef;
00394 
00399     double face_vis_angle_coef;
00400 
00405     double corner_const_coef;
00406 
00411     double corner_range_coef;
00412 
00419     double faceRelErrStDev;
00420 
00427     double cornerRelErrStDev;
00428 
00432     double lp;
00433     
00439     double updateObsLP(SonarObs& o, bool init = false) const;
00440 
00441   public:
00442 
00461     ArakPosteriorSonarObs(const ArakProcess& prior, 
00462         const Arak::Util::PropertyMap& props);
00463 
00467     virtual ~ArakPosteriorSonarObs();
00468 
00473     const Geometry::Rectangle& boundary() const { 
00474       return obsIndex->boundary(); 
00475     }
00476 
00480     virtual double scale() const { return prior.scale(); }
00481 
00490     virtual double logMeasure() const;
00491 
00499     virtual double potential() const;
00500 
00508     virtual void visualize(CGAL::Qt_widget& widget) const;
00509 
00518     virtual void update(const Geometry::Point& a,
00519       const Geometry::Point& b,
00520       const Geometry::Point& c);
00521       
00530     virtual void recolored(const Geometry::Point& a,
00531          const Geometry::Point& b,
00532          const Geometry::Point& c);
00533       
00546     virtual void recolored(const Geometry::Point& a,
00547          const Geometry::Point& b,
00548          const Geometry::Point& c,
00549          const Geometry::Point& d);
00550     
00569     inline double returnProb(const SonarImpact& impact) const {
00570       if (impact.isCorner()) 
00571   return 1.0 / (1.0 + 
00572           exp(-(corner_const_coef + 
00573           (corner_range_coef * impact.min_range))));
00574       else
00575   return 1.0 / (1.0 + 
00576           exp(-(face_const_coef + 
00577           (face_proj_angle_coef * log(sin(impact.proj_angle))) +
00578           (face_min_range_coef * impact.min_range) +
00579           (face_vis_angle_coef * impact.visible_angle))));
00580     }
00581 
00591     inline double distLikelihood(const SonarImpact& impact,
00592          const double obs) const {
00593       double stdev = impact.min_range * 
00594   (impact.isCorner() ? cornerRelErrStDev : faceRelErrStDev);
00595       double var = stdev * stdev;
00596       double dist = (obs - impact.min_range);
00597       // TODO: this should be a truncated Gaussian
00598       return exp(- (dist * dist) / (2.0 * var)) / (stdev * sqrt(2.0 * M_PI));
00599     } 
00600 
00605     template <typename ImpactIterator>
00606     inline double likelihood(double range,
00607            ImpactIterator begin,
00608            ImpactIterator end) const {
00609       bool is_max_range = (range >= maxRange);
00610       double no_prev_returns_prob = 1.0;
00611       double likelihood = 0.0;
00612       // Step through the sonar contacts in sorted order, adding in
00613       // the likelihood of the observation given the contact.
00614       while (begin != end) {
00615   const SonarImpact& impact = *begin;
00616   double return_prob = returnProb(impact);
00617   if (!is_max_range)
00618     likelihood += return_prob * no_prev_returns_prob *
00619       distLikelihood(impact, range);
00620   no_prev_returns_prob *= (1.0 - return_prob);
00621   ++begin;
00622       }
00623       // Add in the likelihood that comes from the background model,
00624       // which is an outlier density with a spike at the max-range
00625       // value.
00626       if (is_max_range)
00627   likelihood += no_prev_returns_prob * prob_max_range;
00628       else
00629   likelihood += no_prev_returns_prob * (1.0 - prob_max_range)
00630     * (// uniform outlier model
00631        (unif_outlier_weight / maxRange)
00632              +
00633        // exponential outlier model
00634        (1.0 - unif_outlier_weight) * 
00635        exp_outlier_coef * exp(-exp_outlier_coef * (maxRange - range)));
00636       // Return the likelihood.
00637       return likelihood;
00638     }
00639 
00640   }; // End of class: ArakPosteriorSonarObs 
00641 
00650   CGAL::Qt_widget& operator<<(CGAL::Qt_widget& widget, 
00651             ArakPosteriorSonarObs& p);
00652 
00653 }
00654 
00655 #endif

Generated on Wed May 25 14:39:19 2005 for Arak by doxygen 1.3.6