00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00049 
00050 
00051 
00052 #include <map>
00053 #include <set>
00054 #include <vector>
00055 #include <limits>
00056 #include <stdexcept>
00057 #include "Image.h"
00058 #include "LevelSetFunction.h"
00059 #include "Mask.h"
00060 #include "cimg_dependent.h" 
00061 #include <iostream> 
00062 
00063 
00064 
00065 
00066 const double UNDEF_VAL = 100000; 
00067 
00068 using namespace std;
00069 using namespace lsseg;
00070 using namespace boost;
00071 
00072 namespace { 
00073 
00074 
00075 
00076 
00077 
00078 struct Coord2D
00079 
00080 {
00081     Coord2D(int x, int y) : x_(x), y_(y) {}
00082     template<int I> const int& get() const ;
00083 
00084     int x_, y_;
00085 };
00086 inline bool operator<(const Coord2D& c1, const Coord2D& c2) { 
00087     if (c1.y_ != c2.y_) 
00088         return (c1.y_ < c2.y_); 
00089     return (c1.x_ < c2.x_); 
00090 }
00091 inline bool operator==(const Coord2D& c1, const Coord2D& c2) {
00092     return (c1.x_ == c2.x_) && (c1.y_ == c2.y_);
00093 }
00094 template<> const int& Coord2D::get<0>() const {return x_;}
00095 template<> const int& Coord2D::get<1>() const {return y_;}
00096 
00097 template<size_t MUL>
00098 class HashCoord2D
00099 {
00100 public:
00101     size_t operator()(const Coord2D& c) const {return c.y_ * MUL + c.x_;}
00102 };
00103 
00104 
00105 struct Coord3D
00106 
00107 {
00108     Coord3D(int x, int y, int z) : x_(x), y_(y), z_(z) {}
00109     template<int I> const int& get() const ;
00110 
00111     int x_, y_, z_;
00112 };
00113 inline bool operator<(const Coord3D& c1, const Coord3D& c2) {
00114     if (c1.z_ != c2.z_) return (c1.z_ < c2.z_); 
00115     if (c1.y_ != c2.y_) return (c1.y_ < c2.y_);
00116     return (c1.x_ < c2.x_);
00117 }
00118 
00119 inline bool operator==(const Coord3D& c1, const Coord3D& c2) {
00120     return (c1.x_ == c2.x_) && (c1.y_ == c2.y_) && (c1.z_ == c2.z_);
00121 }
00122 
00123 template<> const int& Coord3D::get<0>() const {return x_;}
00124 template<> const int& Coord3D::get<1>() const {return y_;}
00125 template<> const int& Coord3D::get<2>() const {return z_;}
00126 
00127 template<size_t MUL>
00128 class HashCoord3D
00129 {
00130 public:
00131     size_t operator()(const Coord3D& c) const {return c.x_ + MUL * (c.y_ + MUL * c.z_);}
00132 };
00133 
00134 const size_t MAX_ANTICIPATED_RES=10000;
00135 typedef multimap<double, Coord2D > dist_map_2D; 
00136 typedef multimap<double, Coord3D > dist_map_3D; 
00137 typedef map<Coord2D, dist_map_2D::iterator> coord_map_2D; 
00138 typedef map<Coord3D, dist_map_3D::iterator> coord_map_3D; 
00139 
00140 
00141 void init_zero_level_interface_2D(const LevelSetFunction&, LevelSetFunction&, const Mask* m);
00142 void init_zero_level_interface_3D(const LevelSetFunction&, LevelSetFunction&, const Mask* m);
00143     
00144 void init_tentative_values_2D(const LevelSetFunction&, dist_map_2D&, dist_map_2D&, const Mask* m);
00145 void init_tentative_values_3D(const LevelSetFunction&, dist_map_3D&, dist_map_3D&, const Mask* m);
00146 
00147 double compute_dist_estimate_2D(const double x1, const double x2, 
00148                                 const double y1, const double y2);
00149 double compute_dist_estimate_3D(const double x1, const double x2, 
00150                                 const double y1, const double y2, 
00151                                 const double z1, const double z2);
00152 
00153 void march_out_2D(dist_map_2D& tentatives, 
00154                   coord_map_2D& inv_tent, 
00155                   LevelSetFunction& target,
00156                   const Mask* m,
00157                   bool negative);
00158 void march_out_3D(dist_map_3D& tentatives, 
00159                   coord_map_3D& inv_tent, 
00160                   LevelSetFunction& target,
00161                   const Mask* m,
00162                   bool negative);
00163 inline double distance_poly(double d1, double d2);
00164 inline double distance_poly(double d1, double d2, double d3);
00165 }; 
00166 
00167 namespace lsseg {
00168 
00169 
00170 void LevelSetFunction::reinitialize2D(const Mask* m)
00171 
00172 {
00173     
00174     
00175     
00176 
00177     MESSAGE_IF(dimz() > 1, "Warning: applying 2D method on a grid with dim(z) > 1");
00178     assert(!m || size_compatible(*m));
00179 
00180     
00181     
00182 
00183     static LevelSetFunction res; 
00184                                  
00185     res.resize(*this);
00186     res = UNDEF_VAL;
00187 
00188     init_zero_level_interface_2D(*this, res, m);
00189 
00190     
00191     
00192     dist_map_2D pos_tentatives, neg_tentatives;
00193     coord_map_2D pos_tent_inv, neg_tent_inv;
00194     init_tentative_values_2D(res, pos_tentatives, neg_tentatives, m);
00195     
00196     
00197     
00198     for (dist_map_2D::iterator it = pos_tentatives.begin(); it != pos_tentatives.end(); ++it) {
00199         pos_tent_inv[it->second] = it;
00200     }
00201     for (dist_map_2D::iterator it = neg_tentatives.begin(); it != neg_tentatives.end(); ++it) {
00202         neg_tent_inv[it->second] = it;
00203     }
00204 
00205     
00206     march_out_2D(pos_tentatives, pos_tent_inv, res, m, false);
00207     
00208     march_out_2D(neg_tentatives, neg_tent_inv, res, m, true);
00209 
00210     assert(pos_tentatives.empty());
00211     assert(neg_tentatives.empty());
00212     assert(pos_tent_inv.empty());
00213     assert(neg_tent_inv.empty());
00214     
00215     if (!m) { 
00216         swap(res);
00217     } else {
00218         
00219         const double* res_pt = res.begin();
00220         const char* mask_pt = m->begin();
00221         for (double* phi_pt = begin(); phi_pt != end(); ++phi_pt, ++res_pt, ++mask_pt) {
00222             if (*mask_pt) {
00223                 if (*res_pt != UNDEF_VAL) {
00224                     *phi_pt = *res_pt;
00225                 } else {
00226                     
00227                     
00228                     
00229                     *phi_pt = (*phi_pt > 0) ? 1: -1;
00230                 }
00231             }
00232         }
00233     }
00234 }
00235 
00236 
00237 void LevelSetFunction::reinitialize3D(const Mask* m)
00238 
00239 {
00240     
00241     
00242     
00243     assert(!m || size_compatible(*m));
00244 
00245     if (dimz() == 1) {
00246         return reinitialize2D(m); 
00247     }
00248 
00249     
00250     
00251 
00252     static LevelSetFunction res; 
00253                                  
00254     res.resize(*this);
00255     res = UNDEF_VAL;
00256     init_zero_level_interface_3D(*this, res, m);
00257 
00258     
00259     
00260     dist_map_3D pos_tentatives, neg_tentatives;
00261     coord_map_3D pos_tent_inv, neg_tent_inv;
00262     init_tentative_values_3D(res, pos_tentatives, neg_tentatives, m);
00263     
00264     
00265     
00266     for (dist_map_3D::iterator it = pos_tentatives.begin(); it != pos_tentatives.end(); ++it) {
00267         pos_tent_inv[it->second] = it;
00268     }
00269     for (dist_map_3D::iterator it = neg_tentatives.begin(); it != neg_tentatives.end(); ++it) {
00270         neg_tent_inv[it->second] = it;
00271     }
00272 
00273     
00274     march_out_3D(pos_tentatives, pos_tent_inv, res, m, false);
00275     
00276     march_out_3D(neg_tentatives, neg_tent_inv, res, m, true);
00277 
00278     assert(pos_tentatives.empty());
00279     assert(neg_tentatives.empty());
00280     assert(pos_tent_inv.empty());
00281     assert(neg_tent_inv.empty());
00282     
00283     if (!m) { 
00284         swap(res);
00285     } else {
00286         
00287         double* res_pt = res.begin();
00288         for (double* phi_pt = begin(); phi_pt != end(); ++phi_pt, ++res_pt) {
00289             if (*res_pt != UNDEF_VAL) {
00290                 *phi_pt = *res_pt;
00291             }
00292         }
00293     }
00294 }
00295 
00296 
00297 }; 
00298 
00299 namespace { 
00300 
00301 
00302 void init_zero_level_interface_2D(const lsseg::LevelSetFunction& src, 
00303                                   lsseg::LevelSetFunction& trg,
00304                                   const Mask* m)
00305 
00306 {
00307     
00308     
00309     
00310     const double EPS = 1.0e-10;
00311     const int X = src.dimx();
00312     const int Y = src.dimy();
00313     vector<double> scratch(4);
00314     trg.resize(src);
00315     size_t mask_it = 0;
00316     for (int y = 0; y < Y; ++y) {
00317         for (int x = 0; x < X; ++x) {
00318             if (m && !(*m)[mask_it++]) {
00319                 continue; 
00320             }
00321             scratch.clear();
00322             const double cur = src(x, y);
00323             if (cur == 0.0) { 
00324                 trg(x, y) = 0;
00325                 continue;
00326             }
00327             
00328             if (x > 0 && cur * src(x - 1, y) <= 0) {
00329                 
00330                 const double neigh = src(x - 1, y);
00331                 const double val = cur / (cur - neigh);
00332                 assert (val >= 0 && val <= 1);
00333                 scratch.push_back((val > EPS) ? val : EPS);
00334             }
00335             if (x < X - 1 && cur * src(x + 1, y) <= 0) {
00336                 
00337                 const double neigh = src(x + 1, y);
00338                 const double val = cur / (cur - neigh);
00339                 assert (val >= 0 && val <= 1);
00340                 scratch.push_back((val > EPS) ? val : EPS);
00341             }
00342             if (y > 0 && cur * src(x, y - 1) <= 0) {
00343                 
00344                 const double neigh = src(x, y - 1);
00345                 const double val = cur / (cur - neigh);
00346                 assert (val >= 0 && val <= 1);
00347                 scratch.push_back((val > EPS) ? val : EPS);
00348             }
00349             if (y < Y - 1 && cur * src(x, y + 1) <= 0 ) {
00350                 
00351                 const double neigh = src(x, y + 1);
00352                 const double val = cur / (cur - neigh);
00353                 assert (val >= 0 && val <= 1);
00354                 scratch.push_back((val > EPS) ? val : EPS);
00355             }
00356             if (!scratch.empty()) {
00357                 trg(x, y) = *min_element(scratch.begin(), scratch.end());
00358                 if (cur < 0) {
00359                     trg(x, y) *= -1;
00360                 }
00361             }
00362         }
00363     }
00364 }
00365 
00366 
00367 void init_zero_level_interface_3D(const lsseg::LevelSetFunction& src, 
00368                                   lsseg::LevelSetFunction& trg,
00369                                   const Mask* m)
00370 
00371 {
00372     const double EPS = 1.0e-10;
00373     const int X = src.dimx();
00374     const int Y = src.dimy();
00375     const int Z = src.dimz();
00376     vector<double> scratch(6);
00377     trg.resize(src);
00378     size_t mask_it = 0;
00379     for (int z = 0; z < Z; ++z) {
00380         for (int y = 0; y < Y; ++y) {
00381             for (int x = 0; x < X; ++x) {
00382                 if (m && !(*m)[mask_it++]) {
00383                     continue; 
00384                 }
00385                 scratch.clear();
00386                 const double cur = src(x, y, z);
00387                 if (cur == 0.0) { 
00388                     trg(x, y, z) = 0;
00389                     continue;
00390                 }
00391                 
00392                 if (x > 0 && cur * src(x - 1, y, z) <= 0) {
00393                     
00394                     const double neigh = src(x - 1, y, z);
00395                     const double val = cur / (cur - neigh);
00396                     assert (val >= 0 && val <= 1);
00397                     scratch.push_back((val > EPS) ? val : EPS);
00398                 }
00399                 if (x < X - 1 && cur * src(x + 1, y, z) <= 0) {
00400                     
00401                     const double neigh = src(x + 1, y, z);
00402                     const double val = cur / (cur - neigh);
00403                     assert (val >= 0 && val <= 1);
00404                     scratch.push_back((val > EPS) ? val : EPS);
00405                 }
00406                 if (y > 0 && cur * src(x, y - 1, z) <= 0) {
00407                     
00408                     const double neigh = src(x, y - 1, z);
00409                     const double val = cur / (cur - neigh);
00410                     assert (val >= 0 && val <= 1);
00411                     scratch.push_back((val > EPS) ? val : EPS);
00412                 }
00413                 if (y < Y - 1 && cur * src(x, y + 1, z) <= 0 ) {
00414                     
00415                     const double neigh = src(x, y + 1, z);
00416                     const double val = cur / (cur - neigh);
00417                     assert (val >= 0 && val <= 1);
00418                     scratch.push_back((val > EPS) ? val : EPS);
00419                 }
00420                 if (z > 0 && cur * src(x, y ,z - 1) <= 0) {
00421                     
00422                     const double neigh = src(x, y, z - 1);
00423                     const double val = cur / (cur - neigh);
00424                     assert(val >= 0 && val <= 1);
00425                     scratch.push_back((val > EPS) ? val : EPS);
00426                 }
00427                 if (z < Z - 1 && cur * src(x, y, z + 1) <= 0) {
00428                     
00429                     const double neigh = src(x, y, z+1);
00430                     const double val = cur / (cur - neigh);
00431                     assert(val >= 0 && val <= 1);
00432                     scratch.push_back((val > EPS) ? val : EPS);
00433                 }
00434                 if (!scratch.empty()) {
00435                     trg(x, y, z) = *min_element(scratch.begin(), scratch.end());
00436                     if (cur < 0) {
00437                         trg(x, y, z) *= -1;
00438                     }
00439                 }
00440             }
00441         }
00442     }
00443 }
00444 
00445 
00446 void init_tentative_values_2D(const lsseg::LevelSetFunction& phi, 
00447                               dist_map_2D& positive_map,
00448                               dist_map_2D& negative_map, 
00449                               const Mask* m)
00450 
00451 {
00452     positive_map.clear();
00453     negative_map.clear();
00454     const int X = phi.dimx();
00455     const int Y = phi.dimy();
00456 
00457     
00458     set<Coord2D > candidates;
00459     if (!m) { 
00460         for (int y = 0; y < Y; ++y) {
00461             for (int x = 0; x < X; ++x) {
00462                 if (phi(x, y) != UNDEF_VAL) {
00463                     
00464                     if (x > 0 && phi(x-1, y) == UNDEF_VAL) {
00465                         candidates.insert(Coord2D(x-1, y));
00466                     }
00467                     if (x < X-1 && phi(x+1, y) == UNDEF_VAL) {
00468                         candidates.insert(Coord2D(x+1, y));
00469                     }
00470                     if (y > 0 && phi(x, y-1) == UNDEF_VAL) {
00471                         candidates.insert(Coord2D(x, y-1));
00472                     }
00473                     if (y < Y-1 && phi(x, y+1) == UNDEF_VAL) {
00474                         candidates.insert(Coord2D(x, y+1));
00475                     }
00476                 }
00477             }
00478         }
00479     } else { 
00480         size_t mask_it = 0;
00481         for (int y = 0; y < Y; ++y) {
00482             for (int x = 0; x < X; ++x) {
00483                 if ((*m)[mask_it++]) {
00484                     if (phi(x, y) != UNDEF_VAL) {
00485                         
00486                         if (x > 0 && phi(x-1, y) == UNDEF_VAL && (*m)(x-1, y)) {
00487                             candidates.insert(Coord2D(x-1, y));
00488                         }
00489                         if (x < X-1 && phi(x+1, y) == UNDEF_VAL && (*m)(x+1, y)) {
00490                             candidates.insert(Coord2D(x+1, y));
00491                         }
00492                         if (y > 0 && phi(x, y-1) == UNDEF_VAL && (*m)(x, y-1)) {
00493                             candidates.insert(Coord2D(x, y-1));
00494                         }
00495                         if (y < Y-1 && phi(x, y+1) == UNDEF_VAL && (*m)(x, y+1)) {
00496                             candidates.insert(Coord2D(x, y+1));
00497                         }
00498                     }
00499                 }
00500             }
00501         }
00502     }
00503 
00504     
00505     set<Coord2D >::const_iterator it;
00506     double l, r, b, t; 
00507     for (it = candidates.begin(); it != candidates.end(); ++it) {
00508         const int x = it->get<0>();
00509         const int y = it->get<1>();
00510         l = (x > 0)   ? phi(x-1, y) : UNDEF_VAL;
00511         r = (x < X-1) ? phi(x+1, y) : UNDEF_VAL;
00512         b = (y > 0)   ? phi(x, y-1) : UNDEF_VAL;
00513         t = (y < Y-1) ? phi(x, y+1) : UNDEF_VAL;
00514 
00515         double estimate = compute_dist_estimate_2D(l, r, b, t);
00516 
00517         if (estimate > 0) {
00518             positive_map.insert(pair<double, Coord2D >(estimate, *it)); 
00519         } else {
00520             negative_map.insert(pair<double, Coord2D >(estimate, *it)); 
00521         }       
00522     }
00523 }
00524 
00525 
00526 void init_tentative_values_3D(const lsseg::LevelSetFunction& phi, 
00527                               dist_map_3D& positive_map,
00528                               dist_map_3D& negative_map, 
00529                               const Mask* m)
00530 
00531 {
00532     positive_map.clear();
00533     negative_map.clear();
00534     const int X = phi.dimx();
00535     const int Y = phi.dimy();
00536     const int Z = phi.dimz();
00537 
00538     
00539     set<Coord3D > candidates;
00540     if (!m) { 
00541         for (int z = 0; z < Z; ++z) {
00542             for (int y = 0; y < Y; ++y) {
00543                 for (int x = 0; x < X; ++x) {
00544                     if (phi(x, y, z) != UNDEF_VAL) {
00545                         
00546                         if (x > 0 && phi(x-1, y, z) == UNDEF_VAL) {
00547                             candidates.insert(Coord3D(x-1, y, z));
00548                         }
00549                         if (x < X-1 && phi(x+1, y, z) == UNDEF_VAL) {
00550                             candidates.insert(Coord3D(x+1, y, z));
00551                         }
00552                         if (y > 0 && phi(x, y-1, z) == UNDEF_VAL) {
00553                             candidates.insert(Coord3D(x, y-1, z));
00554                         }
00555                         if (y < Y-1 && phi(x, y+1, z) == UNDEF_VAL) {
00556                             candidates.insert(Coord3D(x, y+1, z));
00557                         }
00558                         if (z > 0 && phi(x, y, z-1) == UNDEF_VAL) {
00559                             candidates.insert(Coord3D(x, y, z-1));
00560                         }
00561                         if (z < Z-1 && phi(x, y, z+1) == UNDEF_VAL) {
00562                             candidates.insert(Coord3D(x, y, z+1));
00563                         }
00564                     }
00565                 }
00566             }
00567         }
00568     } else { 
00569         size_t mask_it = 0;
00570         for (int z = 0; z < Z; ++z) {
00571             for (int y = 0; y < Y; ++y) {
00572                 for (int x = 0; x < X; ++x) {
00573                     if ((*m)[mask_it++]) {
00574                         if (phi(x, y, z) != UNDEF_VAL) {
00575                             
00576                             if (x > 0 && phi(x-1, y, z) == UNDEF_VAL && (*m)(x-1, y, z)) {
00577                                 candidates.insert(Coord3D(x-1, y, z));
00578                             }
00579                             if (x < X-1 && phi(x+1, y, z) == UNDEF_VAL && (*m)(x+1, y, z)) {
00580                                 candidates.insert(Coord3D(x+1, y, z));
00581                             }
00582                             if (y > 0 && phi(x, y-1, z) == UNDEF_VAL && (*m)(x, y-1, z)) {
00583                                 candidates.insert(Coord3D(x, y-1, z));
00584                             }
00585                             if (y < Y-1 && phi(x, y+1, z) == UNDEF_VAL && (*m)(x, y+1, z)) {
00586                                 candidates.insert(Coord3D(x, y+1, z));
00587                             }
00588                             if (z > 0 && phi(x, y, z-1) == UNDEF_VAL && (*m)(x, y, z-1)) {
00589                                 candidates.insert(Coord3D(x, y, z-1));
00590                             }
00591                             if (z < Z-1 && phi(x, y, z+1) == UNDEF_VAL && (*m)(x, y, z+1)) {
00592                                 candidates.insert(Coord3D(x, y, z+1));
00593                             }
00594                         }
00595                     }
00596                 }
00597             }
00598         }
00599     }
00600 
00601     
00602     set<Coord3D >::const_iterator it;
00603     double l, r, f, b, u, d; 
00604     for (it = candidates.begin(); it != candidates.end(); ++it) {
00605         const int x = it->get<0>();
00606         const int y = it->get<1>();
00607         const int z = it->get<2>();
00608         l = (x > 0) ? phi(x-1, y, z) : UNDEF_VAL;
00609         r = (x < X-1) ? phi(x+1, y, z) : UNDEF_VAL;
00610         f = (y > 0) ? phi(x, y-1, z) : UNDEF_VAL;
00611         b = (y < Y-1) ? phi(x, y+1, z) : UNDEF_VAL;
00612         u = (z > 0) ? phi(x, y, z-1) : UNDEF_VAL;
00613         d = (z < Z-1) ? phi(x, y, z+1) : UNDEF_VAL;
00614 
00615         double estimate = compute_dist_estimate_3D(l, r, f, b, u, d);
00616 
00617         if (estimate > 0) {
00618             positive_map.insert(pair<double, Coord3D >(estimate, *it)); 
00619         } else {
00620             negative_map.insert(pair<double, Coord3D >(estimate, *it)); 
00621         }       
00622     }
00623 }
00624 
00625 
00626 double compute_dist_estimate_2D(const double x1, const double x2,
00627                                 const double y1, const double y2)
00628 
00629 {
00630     assert(x1 * x2 >= 0 || (x1 == UNDEF_VAL || x2 == UNDEF_VAL));
00631     assert(y1 * y2 >= 0 || (y1 == UNDEF_VAL || y2 == UNDEF_VAL)); 
00632     assert(x1 * y1 >= 0 || (x1 == UNDEF_VAL || y1 == UNDEF_VAL)); 
00633 
00634     const double fac = (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0) ? -1 : 1; 
00635     const double x_min = fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2);
00636     const double y_min = fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2);
00637 
00638     if (x_min == UNDEF_VAL) {
00639         assert (y_min != UNDEF_VAL);
00640         return fac * (y_min + 1);
00641     } 
00642     if (y_min == UNDEF_VAL) {
00643         assert (x_min != UNDEF_VAL);
00644         return fac * (x_min + 1);
00645     }
00646 
00647     
00648     
00649     
00650 
00651     
00652     return fac * distance_poly(x_min, y_min);
00653 }
00654 
00655 
00656 double compute_dist_estimate_3D(const double x1, const double x2,
00657                                 const double y1, const double y2,
00658                                 const double z1, const double z2)
00659 
00660 {
00661     assert(x1 * x2 >= 0 || (x1 == UNDEF_VAL || x2 == UNDEF_VAL));
00662     assert(y1 * y2 >= 0 || (y1 == UNDEF_VAL || y2 == UNDEF_VAL)); 
00663     assert(z1 * z2 >= 0 || (z1 == UNDEF_VAL || z2 == UNDEF_VAL));
00664     assert(x1 * y1 >= 0 || (x1 == UNDEF_VAL || y1 == UNDEF_VAL)); 
00665     assert(x1 * z1 >= 0 || (x1 == UNDEF_VAL || z1 == UNDEF_VAL));
00666 
00667     const double fac = 
00668         (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0 || z1 < 0 || z2 < 0) ? -1 : 1; 
00669 
00670     const double x_min = fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2);
00671     const double y_min = fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2);
00672     const double z_min = fabs(z1) < fabs(z2) ? fabs(z1) : fabs(z2); 
00673 
00674     
00675     
00676 
00677     if (y_min == UNDEF_VAL && z_min == UNDEF_VAL) {
00678         assert(x_min != UNDEF_VAL);
00679         return fac * (x_min + 1);
00680     } else if (x_min == UNDEF_VAL && z_min == UNDEF_VAL) {
00681         assert(y_min != UNDEF_VAL);
00682         return fac * (y_min + 1);
00683     } else if (x_min == UNDEF_VAL && y_min == UNDEF_VAL) {
00684         assert(z_min != UNDEF_VAL);
00685         return fac * (z_min + 1);
00686     } else if (x_min == UNDEF_VAL) {
00687         assert(y_min != UNDEF_VAL && z_min != UNDEF_VAL);
00688         return fac * distance_poly(y_min, z_min); 
00689     } else if (y_min == UNDEF_VAL) {
00690         assert(x_min != UNDEF_VAL && z_min != UNDEF_VAL);
00691         return fac * distance_poly(x_min, z_min);
00692     } else if (z_min == UNDEF_VAL) {
00693         assert(x_min != UNDEF_VAL && y_min != UNDEF_VAL);
00694         return fac * distance_poly(x_min, y_min);
00695     } 
00696 
00697     
00698     return fac * distance_poly(x_min, y_min, z_min);
00699 }
00700 
00701 
00702 double distance_poly(double d1, double d2)
00703 
00704 {
00705     
00706     double ccheck = fabs(d1 - d2);
00707     if (ccheck > 1) {
00708         
00709         
00710         return d1 < d2 ? (d1 + 1) : (d2 + 1);
00711     }
00712 
00713     const double b = -2 * (d1 + d2);
00714     const double c = (d1 * d1) + (d2 * d2) - 1;
00715     const double discriminant = b * b - 8 * c;
00716     assert(discriminant >= 0); 
00717     return 0.25 * (-b + sqrt(discriminant));
00718 }
00719 
00720 
00721 
00722 double distance_poly(double d1, double d2, double d3)
00723 
00724 {
00725     
00726     if (d1 > d2) swap(d1, d2);
00727     if (d2 > d3) swap(d2, d3);
00728     if (d1 > d2) swap(d1, d2);
00729     assert(d1 <= d2 && d2 <= d3);
00730 
00731     
00732     const double tmp1 = d3 - d1;
00733     const double tmp2 = d3 - d2;
00734     const double ccheck = (tmp1 * tmp1) + (tmp2 * tmp2);
00735     if (ccheck > 1) {
00736         
00737         return distance_poly(d1, d2);
00738     } 
00739     
00740     const double six_inv = double(1) / double(6);
00741     
00742     const double b = -2 * (d1 + d2 + d3);
00743     const double c = (d1 * d1) + (d2 * d2) + (d3 * d3) - 1;
00744     const double discriminant = (b * b - 12 * c);
00745     assert(discriminant >= 0); 
00746     return six_inv * (-b + sqrt(discriminant));
00747 }
00748 
00749 
00750 
00751 void march_out_2D(dist_map_2D& tentatives, 
00752                   coord_map_2D& inv_tent, 
00753                   lsseg::LevelSetFunction& target, 
00754                   const Mask* m,
00755                   bool negative)
00756 
00757 {
00758     const int X = target.dimx();
00759     const int Y = target.dimy();
00760     
00761     dist_map_2D::iterator tmp_it, cur_it;
00762     coord_map_2D::iterator c_it;
00763     
00764     double l, r, b, t; 
00765 
00766     while (!tentatives.empty()) {
00767         if (negative) {
00768             cur_it = tentatives.end();
00769             --cur_it;
00770         } else {
00771             cur_it = tentatives.begin();
00772         }
00773 
00774         const int x = cur_it->second.get<0>();
00775         const int y = cur_it->second.get<1>();
00776         target(x, y) = cur_it->first;
00777         
00778         
00779         if (x > 0 && target(x-1, y) == UNDEF_VAL && (!m || (*m)(x-1, y))) {  
00780             r = cur_it->first;
00781             l = (x > 1) ? target(x-2, y) : UNDEF_VAL;
00782             b = (y > 0) ? target(x-1, y-1) : UNDEF_VAL;
00783             t = (y < Y-1) ? target(x-1, y+1) : UNDEF_VAL;
00784             const double dist = compute_dist_estimate_2D(l, r, b, t);
00785             const Coord2D xy(x-1, y);
00786             c_it = inv_tent.find(xy);
00787             if (c_it != inv_tent.end()) {
00788                 tentatives.erase(c_it->second);
00789             }
00790             tmp_it = tentatives.insert(pair<double, Coord2D >( dist, xy));
00791             inv_tent[xy]= tmp_it;
00792         }
00793         if (x < X-1 && target(x+1, y) == UNDEF_VAL && (!m || (*m)(x+1, y))) { 
00794             r = (x < X-2) ? target(x+2, y) : UNDEF_VAL;
00795             l = cur_it->first;
00796             b = (y > 0) ? target(x+1,y-1) : UNDEF_VAL;
00797             t = (y < Y-1) ? target(x+1, y+1) : UNDEF_VAL;
00798             const double dist = compute_dist_estimate_2D(l, r, b, t);
00799             const Coord2D xy(x+1, y);
00800             c_it = inv_tent.find(xy);
00801             if (c_it != inv_tent.end()) {
00802                 tentatives.erase(c_it->second);
00803             }
00804             tmp_it = tentatives.insert(pair<double, Coord2D >(dist,xy));
00805             inv_tent[xy] = tmp_it;
00806         }
00807         if (y > 0 && target(x, y-1) == UNDEF_VAL && (!m || (*m)(x, y-1))) { 
00808             r = (x < X-1) ? target(x+1, y-1) : UNDEF_VAL;
00809             l = (x > 0) ? target(x-1, y-1) : UNDEF_VAL;
00810             b = (y > 1) ? target(x, y-2) : UNDEF_VAL;
00811             t = cur_it->first;
00812             const double dist = compute_dist_estimate_2D(l, r, b, t);
00813             const Coord2D xy(x, y-1);
00814             c_it = inv_tent.find(xy);
00815             if (c_it != inv_tent.end()) {
00816                 tentatives.erase(c_it->second);
00817             }
00818             tmp_it = tentatives.insert(pair<double, Coord2D >(dist, xy));
00819             inv_tent[xy] = tmp_it;
00820         }
00821         if (y < Y-1 && target(x, y+1) == UNDEF_VAL && (!m || (*m)(x, y+1))) { 
00822             r = (x < X-1) ? target(x+1, y+1) : UNDEF_VAL;
00823             l = (x > 0) ? target(x-1, y+1): UNDEF_VAL;
00824             b = cur_it->first;
00825             t = (Y < Y-2) ? target(x, y+2) : UNDEF_VAL;
00826             const double dist = compute_dist_estimate_2D(l, r, b, t);
00827             const Coord2D xy(x, y+1);
00828             c_it= inv_tent.find(xy);
00829             if (c_it != inv_tent.end()) {
00830                 tentatives.erase(c_it->second);
00831             }
00832             tmp_it = tentatives.insert(pair<double, Coord2D >(dist, xy));
00833             inv_tent[xy] = tmp_it;
00834         }
00835         assert(inv_tent.size() == tentatives.size());
00836         
00837         
00838         assert(inv_tent[cur_it->second] == cur_it);
00839         inv_tent.erase(cur_it->second);
00840         tentatives.erase(cur_it);
00841     }
00842 }
00843 
00844 
00845 void march_out_3D(dist_map_3D& tentatives, 
00846                   coord_map_3D& inv_tent, 
00847                   LevelSetFunction& target,
00848                   const Mask* m,
00849                   bool negative)
00850 
00851 {
00852     const int X = target.dimx();
00853     const int Y = target.dimy();
00854     const int Z = target.dimz();
00855     
00856     dist_map_3D::iterator tmp_it, cur_it;
00857     coord_map_3D::iterator c_it;
00858 
00859     double l, r, f, b, u, d; 
00860 
00861     while (!tentatives.empty()) {
00862         if (negative) {
00863             cur_it = tentatives.end();
00864             --cur_it;
00865         } else {
00866             cur_it = tentatives.begin();
00867         }
00868 
00869         const int x = cur_it->second.get<0>();
00870         const int y = cur_it->second.get<1>();
00871         const int z = cur_it->second.get<2>();
00872         target(x, y, z) = cur_it->first;
00873         
00874         
00875 
00876         
00877         if (x > 0 && target(x-1, y, z) == UNDEF_VAL && (!m || (*m)(x-1, y, z))) {  
00878             r = cur_it->first;
00879             l = (x > 1) ? target(x-2, y, z) : UNDEF_VAL;
00880             b = (y > 0) ? target(x-1, y-1, z) : UNDEF_VAL;
00881             f = (y < Y-1) ? target(x-1, y+1, z) : UNDEF_VAL;
00882             d = (z > 0) ? target(x-1, y, z-1) : UNDEF_VAL;
00883             u = (z < Z-1) ? target(x-1, y, z+1) : UNDEF_VAL;
00884             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00885             const Coord3D xyz(x-1, y, z);
00886             c_it = inv_tent.find(xyz);
00887             if (c_it != inv_tent.end()) {
00888                 tentatives.erase(c_it->second);
00889             }
00890             tmp_it = tentatives.insert(pair<double, Coord3D >( dist, xyz));
00891             inv_tent[xyz]= tmp_it;
00892         }
00893 
00894         
00895         if (x < X-1 && target(x+1, y, z) == UNDEF_VAL && (!m || (*m)(x+1, y, z))) { 
00896             r = (x < X-2) ? target(x+2, y, z) : UNDEF_VAL;
00897             l = cur_it->first;
00898             b = (y > 0) ? target(x+1,y-1, z) : UNDEF_VAL;
00899             f = (y < Y-1) ? target(x+1, y+1, z) : UNDEF_VAL;
00900             d = (z > 0) ? target(x+1, y, z-1) : UNDEF_VAL;
00901             u = (z < Z-1) ? target(x+1, y, z+1) : UNDEF_VAL;
00902             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00903             const Coord3D xyz(x+1, y, z);
00904             c_it = inv_tent.find(xyz);
00905             if (c_it != inv_tent.end()) {
00906                 tentatives.erase(c_it->second);
00907             }
00908             tmp_it = tentatives.insert(pair<double, Coord3D >(dist,xyz));
00909             inv_tent[xyz] = tmp_it;
00910         }
00911 
00912         
00913         if (y > 0 && target(x, y-1, z) == UNDEF_VAL && (!m || (*m)(x, y-1, z))) { 
00914             r = (x < X-1) ? target(x+1, y-1, z) : UNDEF_VAL;
00915             l = (x > 0) ? target(x-1, y-1, z) : UNDEF_VAL;
00916             b = (y > 1) ? target(x, y-2, z) : UNDEF_VAL;
00917             f = cur_it->first;
00918             d = (z > 0) ? target(x, y-1, z-1) : UNDEF_VAL;
00919             u = (z < Z-1) ? target(x, y-1, z+1) : UNDEF_VAL;
00920             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00921             const Coord3D xyz(x, y-1, z);
00922             c_it = inv_tent.find(xyz);
00923             if (c_it != inv_tent.end()) {
00924                 tentatives.erase(c_it->second);
00925             }
00926             tmp_it = tentatives.insert(pair<double, Coord3D >(dist, xyz));
00927             inv_tent[xyz] = tmp_it;
00928         }
00929 
00930         
00931         if (y < Y-1 && target(x, y+1, z) == UNDEF_VAL && (!m || (*m)(x, y+1, z))) { 
00932             r = (x < X-1) ? target(x+1, y+1, z) : UNDEF_VAL;
00933             l = (x > 0) ? target(x-1, y+1, z): UNDEF_VAL;
00934             b = cur_it->first;
00935             f = (Y < Y-2) ? target(x, y+2, z) : UNDEF_VAL;
00936             d = (z > 0) ? target(x, y+1, z-1) : UNDEF_VAL;
00937             u = (z < Z-1) ? target(x, y+1, z+1) : UNDEF_VAL;
00938             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00939             const Coord3D xyz(x, y+1, z);
00940             c_it= inv_tent.find(xyz);
00941             if (c_it != inv_tent.end()) {
00942                 tentatives.erase(c_it->second);
00943             }
00944             tmp_it = tentatives.insert(pair<double, Coord3D >(dist, xyz));
00945             inv_tent[xyz] = tmp_it;
00946         }
00947         
00948         if (z > 0 && target(x, y, z-1) == UNDEF_VAL && (!m || (*m)(x, y, z-1))) {
00949             r = (x < X-1) ? target(x+1, y, z-1) : UNDEF_VAL;
00950             l = (x > 0) ? target(x-1, y, z-1) : UNDEF_VAL;
00951             b = (y > 0) ? target(x, y-1, z-1) : UNDEF_VAL;
00952             f = (y < Y-1) ? target(x, y+1, z-1) : UNDEF_VAL;
00953             d = (z > 1) ? target(x, y, z-2) : UNDEF_VAL;
00954             u = cur_it->first;
00955             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00956             const Coord3D xyz(x, y, z-1);
00957             c_it = inv_tent.find(xyz);
00958             if (c_it != inv_tent.end()) {
00959                 tentatives.erase(c_it->second);
00960             }
00961             tmp_it = tentatives.insert(pair<double, Coord3D >(dist, xyz));
00962             inv_tent[xyz] = tmp_it;
00963         }
00964 
00965         
00966         if (z < Z-1 && target(x, y, z+1) == UNDEF_VAL && (!m || (*m)(x, y, z+1))) {
00967             r = (x < X-1) ? target(x+1, y, z+1) : UNDEF_VAL;
00968             l = (x > 0) ? target(x-1, y, z+1) : UNDEF_VAL;
00969             b = (y > 0) ? target(x, y-1, z+1) : UNDEF_VAL;
00970             f = (y < Y-1) ? target(x, y+1, z+1) : UNDEF_VAL;
00971             d = cur_it->first;
00972             u = (z < Z-2) ? target(x, y, z+2) : UNDEF_VAL;
00973             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00974             const Coord3D xyz(x, y, z+1);
00975             c_it = inv_tent.find(xyz);
00976             if (c_it != inv_tent.end()) {
00977                 tentatives.erase(c_it->second);
00978             }
00979             tmp_it = tentatives.insert(pair<double, Coord3D>(dist, xyz));
00980             inv_tent[xyz] = tmp_it;
00981         }
00982         assert(inv_tent.size() == tentatives.size());
00983         
00984         
00985         tentatives.erase(cur_it);
00986         assert(inv_tent[cur_it->second] == cur_it);
00987         inv_tent.erase(cur_it->second);
00988     }
00989 }
00990 
00991 }; 
00992