ReSCue - Retrieval System for Curves
Main Page   Class Hierarchy   Compound List   File List   Compound Members  

extended_fs_graph.h

00001 #ifndef RESCUE__EXTENDED_FS_GRAPH_H
00002 #define RESCUE__EXTENDED_FS_GRAPH_H
00003 
00004 #include <vector>
00005 #include <list>
00006 #include <algorithm>
00007 #include "rescutil.h"
00008 #include "compact_interval_border.h"
00009 
00010 
00011 namespace rescue
00012 {
00013 
00014 
00020 // ==========================================================================================
00021 // ==========================================================================================
00022 template<class transporter_edge>
00023 class extended_fs_graph 
00024 {
00025 
00026 public:
00027 
00028     typedef transporter_edge transporter_edge_class;
00029     typedef transporter_edge::angle_t angle_t;
00030     typedef transporter_edge::index_t index_t;
00031     typedef transporter_edge::arithmetic_t arithmetic;
00032     typedef transporter_edge::interval_border interval_border;
00033     typedef transporter_edge::border_iterator edge_border_iterator;
00034     typedef transporter_edge::point_t point;
00035     typedef transporter_edge::motion motion;
00036 
00037     typedef arithmetic arithmetic_t;
00038 
00039         typedef std::pair<point,point> point_pair;
00040     
00043     typedef transporter_edge::border_value border_value;
00044 
00049     typedef std::pair<index_t,index_t> discrete_free_space_point;
00050 
00054     typedef std::list<discrete_free_space_point> discrete_reparametrization_pair;
00055 
00056     
00057     typedef std::vector<interval_border> border_array;
00058     typedef std::list<interval_border> border_list;
00059     typedef border_array::iterator border_iterator;
00060 
00064     extended_fs_graph();
00065 
00068     ~extended_fs_graph();
00069 
00074     void build(point* P,point* Q,index_t m_P,index_t n_Q, 
00075                 const arithmetic& eps, const arithmetic& delta);
00076 
00080     bool update(const interval_border& update_borders);
00081 
00086         bool find_path();
00087 
00094     motion get_match();
00095 
00099     bool get_reparametrizations(discrete_reparametrization_pair& kappa_lambda);
00100 
00103     void clear();
00104 
00105 private:
00106 
00111     index_t* columns;
00112 
00117     index_t* rows;
00118     
00123     index_t active_columns;
00124     
00129     index_t active_rows;
00130 
00134     border_type prev_border_type;
00135 
00140     index_t m;
00141         
00146     index_t n;
00147         
00151     transporter_edge*** edges; 
00152     
00155     bool*** edge_activated;
00156     
00159     index_t*** activation_step;
00160 
00163     bool** reachable;
00164 
00167     index_t update_step;
00168 
00173     point_pair reference_points;
00174 
00181     border_value match_pos;
00182 
00186     bool match_found;
00187 
00192     border_list interval_borders_list;
00193 
00198     border_array interval_borders;
00199 
00203     void extract_borders(transporter_edge& E, const index_t& i, const index_t& j,
00204         graph_direction dir);
00205 
00208     void sort_borders();
00209 
00210 public:
00211 
00215     border_iterator border_begin();
00216 
00219         border_iterator border_end();
00220 
00221 };
00222 
00223 // ==========================================================================================
00224 // ==========================================================================================
00225 
00226 
00227 
00228 
00229 // ==========================================================================================
00230 template<class transporter_edge>
00231 extended_fs_graph<transporter_edge>::
00232         extended_fs_graph()
00233 // ==========================================================================================
00234 {
00235         m=0;
00236         n=0;
00237         edges = NULL;
00238     rows = NULL;
00239     columns = NULL;
00240     match_found = false;
00241 }
00242 
00243 // ==========================================================================================
00244 template<class transporter_edge>
00245 extended_fs_graph<transporter_edge>::
00246         ~extended_fs_graph()
00247 // ==========================================================================================
00248 {
00249         clear();
00250 }
00251 
00252 // ==========================================================================================
00253 template<class transporter_edge>
00254 extended_fs_graph<transporter_edge>::border_iterator
00255 extended_fs_graph<transporter_edge>::border_begin()
00256 // ==========================================================================================
00257 {
00258     return interval_borders.begin();
00259 }
00260 
00261 // ==========================================================================================
00262 template<class transporter_edge>
00263 extended_fs_graph<transporter_edge>::border_iterator
00264 extended_fs_graph<transporter_edge>::border_end()
00265 // ==========================================================================================
00266 {
00267     return interval_borders.end();
00268 }
00269 
00270 // ==========================================================================================
00271 template<class transporter_edge>
00272 void extended_fs_graph<transporter_edge>::
00273         clear()
00274 // ==========================================================================================
00275 {
00276 
00277     if (rows!=NULL)
00278         delete[] rows;
00279     if (columns!=NULL)
00280         delete[] columns;
00281     rows = NULL;
00282     columns = NULL;
00283 
00284     if (edges!=NULL)
00285     {
00286             for (index_t i=0; i<=m; i++)
00287             {
00288                     for (index_t j=0; j<=n; j++)
00289                     {
00290                             delete[] edges[i][j];
00291                             delete[] edge_activated[i][j];
00292                             delete[] activation_step[i][j];
00293                     }
00294                     delete[] edges[i];
00295                         delete[] edge_activated[i];
00296                         delete[] activation_step[i];
00297                         delete[] reachable[i];
00298             }
00299             delete[] edges;
00300                 delete[] edge_activated;
00301                 delete[] activation_step;
00302                 delete[] reachable;
00303 
00304             edges = NULL;
00305                 edge_activated = NULL;
00306                 activation_step = NULL;
00307                 reachable = NULL;
00308     }
00309 
00310     m = 0;
00311     n = 0;
00312     match_found = false;
00313 
00314 }
00315 
00316 // ==========================================================================================
00317 template<class transporter_edge>
00318 void extended_fs_graph<transporter_edge>::
00319         extract_borders(transporter_edge& E,
00320     const index_t& i, const index_t& j, graph_direction dir)
00321 // ==========================================================================================
00322 {
00323 
00324     edge_border_iterator r_it, r_end, l_it, l_end;
00325 
00326     r_it = E.right_borders_begin();
00327     r_end = E.right_borders_end();
00328     l_it = E.left_borders_begin();
00329     l_end = E.left_borders_end();
00330 
00331     for (; l_it!=l_end; l_it++)
00332     {
00333         transporter_edge::angle_t a = *l_it;
00334         if (a.type!=transporter_edge::angle_t::regular && a.type!=transporter_edge::angle_t::two_pi)
00335             return;
00336         interval_borders_list.push_back(interval_border(a,LEFT_BORDER,i,j,dir));
00337     }
00338 
00339     for (; r_it!=r_end; r_it++)
00340     {
00341         transporter_edge::angle_t a = *r_it;
00342         if (a.type!=transporter_edge::angle_t::regular && a.type!=transporter_edge::angle_t::two_pi)
00343             return;
00344         interval_borders_list.push_back(interval_border(a,RIGHT_BORDER,i,j,dir));
00345     }
00346 
00347 }
00348 
00349 // ==========================================================================================
00350 template<class transporter_edge>
00351 void extended_fs_graph<transporter_edge>::
00352         sort_borders()
00353 // ==========================================================================================
00354 {
00355     
00356     // assign sufficient space to border_intervals
00357     index_t ii = interval_borders_list.size();
00358     interval_borders = border_array(interval_borders_list.size());
00359 
00360     // copy from border_interval_list to border_intervals
00361     //std::copy(
00362     //    interval_borders_list.begin(),interval_borders_list.end(),
00363     //    interval_borders.begin());
00364 
00365     border_list::iterator b_it = interval_borders_list.begin();
00366     border_list::iterator b_end = interval_borders_list.end();
00367 
00368     for (; b_it!=b_end; b_it++)
00369     {
00370         interval_border border = *b_it;
00371         if (!(border.m_value.s<-1. || border.m_value.s>1.))
00372             interval_borders.push_back(border);
00373     }
00374 
00375     // sort border_intervals
00376     std::sort(interval_borders.begin(),interval_borders.end());
00377 
00378     // the unsorted list is needed no mo'.
00379     interval_borders_list.clear();
00380 
00381 }
00382 
00383 // ==========================================================================================
00384 template<class transporter_edge>
00385 bool extended_fs_graph<transporter_edge>::
00386     update(const interval_border& ib)
00387 // ==========================================================================================
00388 {
00389 
00390         index_t i = ib.col();
00391     index_t j = ib.row();
00392     match_pos = ib.val();
00393 
00394     // update suitability-data of currently active intervals
00395     if (ib.type()==LEFT_BORDER)
00396     {
00397         columns[ib.col()]++;
00398         rows[ib.row()]++;
00399         if (rows[ib.row()]==1)
00400             active_rows++;
00401         if (columns[ib.col()]==1)
00402             active_columns++;
00403             // toggle edge activation
00404             edge_activated[i][j][ib.dir()] = true;
00405     } 
00406 
00407 
00408     // determine whether the active configuration of active edges is suitable
00409     // using the suitability information that has just been updated
00410     bool suitable;
00411     if (active_columns>=m && active_rows>=n && 
00412         ib.type()==RIGHT_BORDER && prev_border_type==LEFT_BORDER)
00413         suitable = true;
00414     else
00415         suitable = false;
00416 
00417     border_type prev_border_type = ib.type();
00418 
00419     if (suitable)
00420     {            
00421                 if (find_path())
00422         {
00423                         return true;
00424         }
00425     }
00426 
00427     // The suitability-information for left interval broders
00428     // is updated after the path-update, because the border itself is still contained
00429     // in the intersection.
00430     if (ib.type()==RIGHT_BORDER)
00431     {
00432         columns[ib.col()]--;
00433         rows[ib.row()]--;
00434         if (rows[ib.row()]==0)
00435             active_rows--;
00436         if (columns[ib.col()]==0)
00437             active_columns--;
00438         // toggle edge activation
00439                 edge_activated[i][j][ib.dir()] = false;
00440     }
00441         
00442         return false;
00443 
00444 }
00445 
00446 
00447 // ==========================================================================================
00448 template<class transporter_edge>
00449 void extended_fs_graph<transporter_edge>::
00450         build(point* P,point* Q,index_t m_P,index_t n_Q, 
00451         const arithmetic& eps, const arithmetic& delta)
00452 // ==========================================================================================
00453 {
00454 
00455         clear();
00456 
00457         m = m_P;
00458         n = n_Q;
00459 
00460     update_step = 0;
00461 
00462     // initialize the counters that help to determine the suitability
00463     // of the currently active intervals.
00464     prev_border_type = LEFT_BORDER;
00465     index_t i;
00466     columns = new index_t[m+1];
00467     rows = new index_t[n+1];
00468     for (i=0; i<=m; i++)
00469         columns[i] = 0;
00470     for (i=0; i<=n; i++)
00471         rows[i] = 0;
00472     active_columns = 0;
00473     active_rows = 0;
00474 
00475         edges = new transporter_edge**[m+1];
00476         edge_activated = new bool**[m+1];
00477         activation_step = new index_t**[m+1];
00478     reachable = new bool*[m+1];
00479 
00480         reference_points = point_pair(P[0],Q[0]);
00481         
00482         for (i=0; i<m; i++)
00483         {
00484                 edges[i] = new transporter_edge*[n+1];
00485                 edge_activated[i] = new bool*[n+1];
00486                 activation_step[i] = new index_t*[n+1];
00487         reachable[i] = new bool[n+1];
00488 
00489         for (index_t j=0; j<n; j++)
00490                 {
00491                         edges[i][j] = new transporter_edge[3];
00492                         edge_activated[i][j] = new bool[3];
00493                         activation_step[i][j] = new index_t[3];
00494 
00495                         edges[i][j][horizontal].assign_transporter
00496                                 (point_pair(P[i],P[i+1]),point_pair(Q[j],Q[j]),reference_points,eps,delta);
00497                         edges[i][j][diagonal].assign_transporter
00498                                 (point_pair(P[i],P[i+1]),point_pair(Q[j],Q[j+1]),reference_points,eps,delta);
00499                         edges[i][j][vertical].assign_transporter
00500                                 (point_pair(P[i],P[i]),point_pair(Q[j],Q[j+1]),reference_points,eps,delta);
00501             
00502             // extract interval borders from the three edges just created            
00503             extract_borders(edges[i][j][horizontal],i,j,horizontal);
00504             extract_borders(edges[i][j][diagonal],i,j,diagonal);
00505             extract_borders(edges[i][j][vertical],i,j,vertical);
00506 
00507             // initially, each edge is inactive (until it is activated in an update()-step)
00508             edge_activated[i][j][horizontal] = false;
00509             edge_activated[i][j][diagonal] = false;
00510             edge_activated[i][j][vertical] = false;
00511 
00512             // activation_step 0 means that the edge has never been activated.
00513             activation_step[i][j][horizontal] = 0;
00514             activation_step[i][j][diagonal] = 0;
00515             activation_step[i][j][vertical] = 0;
00516 
00517             // since all edges are inactive, no vertex is reachable
00518             // (except for the source (0,0), but we'll take care of that later...).
00519             reachable[i][j] = false;
00520 
00521                 }
00522 
00523         reachable[i][n] = false;
00524                 edges[i][n] = new transporter_edge[3];
00525                 edge_activated[i][n] = new bool[3];
00526                 activation_step[i][n] = new index_t[3];
00527 
00528                 edges[i][n][horizontal].assign_transporter
00529                                 (point_pair(P[i],P[i+1]),point_pair(Q[n],Q[n]),reference_points,eps,delta);
00530         extract_borders(edges[i][n][horizontal],i,n,horizontal);
00531         edge_activated[i][n][horizontal] = false;
00532         activation_step[i][n][horizontal] = 0;
00533 
00534         }
00535 
00536         edges[m] = new transporter_edge*[n+1];
00537         edge_activated[m] = new bool*[n+1];
00538         activation_step[m] = new index_t*[n+1];
00539     reachable[m] = new bool[n+1];
00540 
00541         for (index_t j=0; j<n; j++)
00542         {
00543         reachable[m][j] = false;
00544 
00545                 edges[m][j] = new transporter_edge[3];
00546                 edge_activated[m][j] = new bool[3];
00547                 activation_step[m][j] = new index_t[3];
00548 
00549         edges[m][j][vertical].assign_transporter
00550                         (point_pair(P[m],P[m]),point_pair(Q[j],Q[j+1]),reference_points,eps,delta);
00551         extract_borders(edges[m][j][vertical],m,j,vertical);
00552 
00553         // initially, each edge is inactive (until it is activated in an update()-step)
00554         edge_activated[m][j][vertical] = false;
00555         // activation_step 0 means that the edge has never been activated.
00556         activation_step[m][j][vertical] = 0;
00557 
00558         }
00559 
00560     reachable[m][n] = false;
00561         edges[m][n] = new transporter_edge[3];
00562         edge_activated[m][n] = new bool[3];
00563         activation_step[m][n] = new index_t[3];
00564 
00565 
00566     // Before we forget: the graph's source (0,0) is always reachable!
00567     reachable[0][0] = true;
00568 
00569     // sort the extracted interval borders
00570     sort_borders();
00571                 
00572 }
00573 
00574 // ==========================================================================================
00575 template<class transporter_edge>
00576 bool extended_fs_graph<transporter_edge>::
00577         find_path()
00578 // ==========================================================================================
00579 {
00580         bool* last_column;
00581         bool* curr_column;
00582 
00583     // use dynamic programming for updating the graph.  
00584 
00585         bool path_found;
00586     match_found = false;
00587 
00588     bool b_v, b_h, b_d;
00589 
00590         // initialize last_row
00591         last_column = reachable[0];
00592 
00593         last_column[0] = true;
00594         for (index_t j=1; j<=n; j++)
00595         {
00596         b_v = edge_activated[0][j-1][vertical];
00597                 last_column[j] = last_column[j-1] && b_v;
00598         }
00599 
00600     // in case m==0, curr_column[m][n] needs to specified...
00601         curr_column = last_column;
00602         index_t i=1;
00603 
00604         // dynamic programming
00605     path_found = true;
00606         for (; i<=m && path_found; i++)
00607         {
00608                 last_column = reachable[i-1];
00609                 curr_column = reachable[i];
00610 
00611                 path_found = false;
00612                 curr_column[0] = false;
00613         b_h = edge_activated[i-1][0][horizontal];
00614                 if (last_column[0] && b_h)
00615                 {
00616                         curr_column[0] = true;
00617                         path_found = true;
00618                 }
00619                 for (index_t j=1; j<=n; j++)
00620                 {
00621                         curr_column[j] = false;
00622 
00623             // if-clause slightly optimized "by hand"
00624             b_d = edge_activated[i-1][j-1][diagonal];                    
00625             if (last_column[j-1] && b_d)
00626                         {
00627                                 curr_column[j] = true;
00628                                 path_found = true;
00629             } else {
00630                 b_v = edge_activated[i][j-1][vertical];
00631                 if (curr_column[j-1] && b_v)
00632                                 {
00633                                         curr_column[j] = true;
00634                                         path_found = true;
00635                 } else {
00636                     b_h = edge_activated[i-1][j][horizontal];
00637                                 if (last_column[j] && b_h)
00638                                     {
00639                                             curr_column[j] = true;
00640                                             path_found = true;
00641                     }
00642                 }
00643             }
00644                 }
00645 
00646         }
00647 
00648         if (curr_column[n])
00649         {
00650         match_found = true;
00651                 return true;
00652         }
00653 
00654         return false;
00655 
00656 }
00657 
00658 
00659 // ==========================================================================================
00660 template<class transporter_edge>
00661 extended_fs_graph<transporter_edge>::motion 
00662     extended_fs_graph<transporter_edge>::get_match()
00663 // ==========================================================================================
00664 {
00665 
00666     if (m==0 && n==0)
00667     {
00668         transporter_edge te;
00669         te.assign_transporter
00670             (point_pair(reference_points.first,reference_points.first),
00671              point_pair(reference_points.second,reference_points.second),
00672              reference_points,1.0,1.0);
00673         return transporter_edge::compute_match(*(te.left_borders_begin()),reference_points);
00674 
00675     }
00676 
00677     if (match_found)
00678     {
00679         return transporter_edge::compute_match(match_pos,reference_points);
00680     }
00681     motion match_motion;
00682     return match_motion;
00683 
00684 }
00685 
00686 // ==========================================================================================
00687 template<class transporter_edge>
00688 bool extended_fs_graph<transporter_edge>::get_reparametrizations
00689     (extended_fs_graph<transporter_edge>::discrete_reparametrization_pair& kappa_lambda)
00690 // ==========================================================================================
00691 {
00692 
00693     kappa_lambda.clear();
00694     int i = m;
00695     int j = n;
00696     kappa_lambda.push_front(discrete_free_space_point(i,j));
00697 
00698     while (i>0 || j>0)
00699     {
00700         if (i>0 && j>0 && reachable[i-1][j-1] && edge_activated[i-1][j-1][diagonal]) {
00701             // activating the following lines inserts a loop for the diagonal edge...
00702                         // discrete_free_space_point x(i,j);
00703             //kappa_lambda.push_front(x);
00704             i--;
00705             j--;
00706                         discrete_free_space_point y(i,j);
00707             kappa_lambda.push_front(y);
00708         } else if (i>0 && reachable[i-1][j] && edge_activated[i-1][j][horizontal]) {
00709             i--;
00710                         discrete_free_space_point x(i,j);
00711             kappa_lambda.push_front(x);
00712         } else if (j>0 && reachable[i][j-1] && edge_activated[i][j-1][vertical]) {
00713             j--;
00714                         discrete_free_space_point x(i,j);
00715             kappa_lambda.push_front(x);
00716         } else {
00717                         return false;
00718                 }
00719     }
00720     
00721     return true;
00722 
00723 }
00724 
00725 
00726 // end of namespace rescue
00727 }
00728 
00729 
00730 #endif
ReSCue - Retrieval System for Curves
Universität Bonn, Institut für Informatik III, 2001