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
00099 Geometry::Line face_line(pmin, pmax);
00100 projection = face_line.projection(source);
00101
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
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
00117
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
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 };
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 };
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
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
00613
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
00624
00625
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 * (
00631 (unif_outlier_weight / maxRange)
00632 +
00633
00634 (1.0 - unif_outlier_weight) *
00635 exp_outlier_coef * exp(-exp_outlier_coef * (maxRange - range)));
00636
00637 return likelihood;
00638 }
00639
00640 };
00641
00650 CGAL::Qt_widget& operator<<(CGAL::Qt_widget& widget,
00651 ArakPosteriorSonarObs& p);
00652
00653 }
00654
00655 #endif