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