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

RWSegmentVector.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------+
00002  | Library QgarLib, graphics analysis and recognition                  |
00003  | Copyright (C) 2002  Qgar Project, LORIA                             |
00004  |                                                                     |
00005  | This library is free software; you can redistribute it and/or       |
00006  | modify it under the terms of the GNU Lesser General Public          |
00007  | License version 2.1, as published by the Free Software Foundation.  |
00008  |                                                                     |
00009  | This library is distributed in the hope that it will be useful,     |
00010  | but WITHOUT ANY WARRANTY; without even the implied warranty of      |
00011  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                |
00012  | See the GNU Lesser General Public License for more details.         |
00013  |                                                                     |
00014  | The GNU Lesser General Public License is included in the file       |
00015  | LICENSE.LGPL, in the root directory of the Qgar packaging. See      |
00016  | http://www.gnu.org/licenses/lgpl.html for the terms of the licence. |
00017  | To receive a paper copy, write to the Free Software Foundation,     |
00018  | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.       |
00019  |                                                                     |
00020  | Contact Project Qgar for any information:                           |
00021  |   LORIA - équipe Qgar                                               |
00022  |   B.P. 239, 54506 Vandoeuvre-lès-Nancy Cedex, France                |
00023  |   email: qgar-contact@loria.fr                                      |
00024  |   http://www.qgar.org/                                              |
00025  *---------------------------------------------------------------------*/
00026 
00027 
00028 
00029 /**
00030  * @file    RWSegmentVector.C
00031  * @brief   Header file of class qgar::RWSegmentVector.
00032  *
00033  * See file for the RWSegmentVector.H interface.
00034  *
00035  * @author  <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Karl Tombre">Karl Tombre</a>
00036  * @date    July 3, 2001  16:37
00037  * @since   Qgar 1.0
00038  */
00039 
00040 
00041 
00042 // STD
00043 #include <vector>
00044 // QGAR
00045 #include <qgarlib/AbstractGenPointChain.H>
00046 #include <qgarlib/math.H>
00047 #include <qgarlib/primitives.H>
00048 #include <qgarlib/RWSegmentVector.H>
00049 
00050 
00051 
00052 using namespace std;
00053 
00054 
00055 namespace qgar
00056 {
00057 
00058 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00059 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00060 // L O C A L    C O N S T A N T S
00061 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00062 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00063 
00064 
00065 const double RWSEGMENTVECTOR_VERY_LARGE_SIGNIFICANCE = 100000.0;
00066 
00067 
00068 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00069 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00070 
00071 
00072 
00073 
00074 
00075 /*---------------------------------------------------------------------*
00076  |                                                                     |
00077  |                 C  L  A  S  S      R  W  T  R  E  E                 |
00078  |                                                                     |
00079  *---------------------------------------------------------------------*/
00080 
00081 // -------------------------------------------------------------------
00082 // C O N S T R U C T O R S 
00083 // -------------------------------------------------------------------
00084 
00085 
00086 // DEFAULT CONSTRUCTOR
00087 
00088 
00089 RWTree::RWTree()
00090 {
00091   // VOID
00092 }
00093 
00094 
00095 // CONSTRUCT FROM INDEXES AND SIGNIFICANCE
00096 
00097 
00098 RWTree::RWTree(int fi, int li, double s)
00099 
00100   : _firstIdx     (fi),
00101     _lastIdx      (li),
00102     _leftChild    (0),
00103     _rightChild   (0),
00104     _significance (s)
00105   
00106 {
00107   // VOID
00108 }
00109 
00110 
00111 // -------------------------------------------------------------------
00112 // D E S T R U C T O R
00113 // -------------------------------------------------------------------
00114 
00115 
00116 // NON-VIRTUAL DESTRUCTOR
00117 
00118 
00119 RWTree::~RWTree()
00120 {
00121   if (_leftChild != 0)
00122     {
00123       delete _leftChild;
00124     }
00125 
00126   if (_rightChild != 0)
00127     {
00128       delete _rightChild;
00129     }
00130 }
00131 
00132 
00133 // -------------------------------------------------------------------
00134 
00135 
00136 
00137 
00138 /*---------------------------------------------------------------------*
00139  |                                                                     |
00140  |      C  L  A  S  S      R  W  S  E  G  M  E  N  T  V E C T O R      |
00141  |                                                                     |
00142  *---------------------------------------------------------------------*/
00143 
00144 // -------------------------------------------------------------------
00145 // C O N S T R U C T O R
00146 // -------------------------------------------------------------------
00147 
00148 
00149 RWSegmentVector::RWSegmentVector(AbstractGenPointChain<int>& aChain,
00150                                  double minDeviation) 
00151 {
00152   if (aChain.empty())
00153     {
00154       return;  // Nothing to do
00155     }
00156 
00157   // Convert chain to a vector of points
00158 
00159   vector<Point> myChain;
00160   aChain.setToBegin();
00161 
00162   while (!aChain.isAtEnd())
00163     {
00164       myChain.push_back(aChain.accessCurrent());
00165       aChain.moveNext();
00166     }
00167 
00168   // Build the tree
00169   _root = buildTree(myChain, 0, (myChain.size() - 1), minDeviation);
00170 
00171   // And now, construct the vector of Segments we want to retrieve
00172   if (_root != 0)
00173     {
00174       addSegmentIfTerminalNode(_root, myChain);
00175     }
00176 
00177   // Post-processing : Can we simplify?
00178   // Based on an idea by Rosin and West...
00179   // *** WAIT AND SEE ***
00180   
00181   // Delete auxiliary data structures
00182   if (_root != 0)
00183     {
00184       delete _root;
00185     }
00186 
00187   _indexes.erase(_indexes.begin(), _indexes.end());
00188 //  _significance.erase(_significance.begin(), _significance.end());
00189 }
00190 
00191 
00192 // -------------------------------------------------------------------
00193 // D E S T R U C T O R
00194 // -------------------------------------------------------------------
00195 
00196 
00197 // VIRTUAL DESTRUCTOR
00198 
00199 RWSegmentVector::~RWSegmentVector()
00200 {
00201   // VOID
00202 }
00203 
00204 
00205 
00206 // -------------------------------------------------------------------
00207 // P R I V A T E   F U N C T I O N S 
00208 // -------------------------------------------------------------------
00209 
00210 
00211 // INTERNAL FUNCTION TO BUILD THE TREE
00212 
00213 
00214 RWTree*
00215 RWSegmentVector::buildTree(vector<Point>& myChain,
00216                            int fidx,
00217                            int lidx,
00218                            double minDeviation)
00219 {
00220   RWTree* myNode = new RWTree(fidx, lidx);
00221 
00222   // Find maximum deviation
00223   double maxDeviation = 0.0;
00224   int whereToCut = fidx;
00225 
00226   if (myChain[fidx] == myChain[lidx]) // Closed curves
00227     {
00228       Point p = myChain[fidx];
00229       for (int i = fidx + 1 ; i < lidx ; ++i)
00230         {
00231           double d = qgDist(p, myChain[i]);
00232           if (d > maxDeviation)
00233             {
00234               whereToCut = i;
00235               maxDeviation = d;
00236             }
00237         }
00238       // If loop too small or max deviation equal to zero, forget it
00239       if ((lidx - fidx + 1) < 4 || maxDeviation < minDeviation)
00240         {
00241           delete myNode;
00242           return 0;
00243         }
00244       else // Otherwise, create a very large significance
00245         {
00246           myNode->setSignificance(RWSEGMENTVECTOR_VERY_LARGE_SIGNIFICANCE);
00247           myNode->setLeftChild(buildTree(myChain, fidx, whereToCut, minDeviation));
00248           myNode->setRightChild(buildTree(myChain, whereToCut, lidx, minDeviation));
00249           searchBestApproximation (myNode);
00250           return myNode;
00251         }
00252     }
00253   else // Open curves
00254     {
00255       for (int i = fidx + 1 ; i < lidx ; ++i)
00256         {
00257           double d = qgDist(myChain[i], myChain[fidx], myChain[lidx]);
00258           if (d > maxDeviation)
00259             {
00260               whereToCut = i;
00261               maxDeviation = d;
00262             }
00263         }
00264 
00265       // If loop too small or max deviation equal to zero, keep as such
00266       if ((lidx - fidx + 1) < 4 || maxDeviation < minDeviation)
00267         {
00268           myNode->setSignificance(maxDeviation / qgDist(myChain[fidx], myChain[lidx]));
00269           return myNode;
00270         }
00271       else // Otherwise, recursive call
00272         {
00273           myNode->setSignificance(maxDeviation / qgDist(myChain[fidx], myChain[lidx]));
00274           myNode->setLeftChild(buildTree(myChain, fidx, whereToCut, minDeviation));
00275           myNode->setRightChild(buildTree(myChain, whereToCut, lidx, minDeviation));
00276           searchBestApproximation (myNode);
00277           return myNode;
00278         }
00279     }
00280 }
00281 
00282 
00283 // SEARCH FOR THE BEST APPROXIMATION IN THE TREE
00284 
00285 
00286 void
00287 RWSegmentVector::searchBestApproximation(RWTree* aNode)
00288 {
00289   // The lowest the signifiance, the best
00290   double bestSignif;
00291   if (aNode->leftChild() == 0)
00292     {
00293       if (aNode->rightChild() != 0)
00294         {
00295           bestSignif = aNode->rightChild()->significance();
00296         }
00297       else
00298         {
00299           bestSignif = aNode->significance();
00300         }
00301     }
00302   else if (aNode->rightChild() == 0)
00303     {
00304       bestSignif = aNode->leftChild()->significance();
00305     }
00306   else if (aNode->leftChild()->significance() < aNode->rightChild()->significance())
00307     {
00308       bestSignif = aNode->leftChild()->significance();
00309     }
00310   else
00311     {
00312       bestSignif = aNode->rightChild()->significance();
00313     }
00314 
00315 
00316   if (bestSignif < aNode->significance())
00317     {
00318       aNode->setSignificance(bestSignif);
00319     }
00320   else
00321     {
00322       if (aNode->leftChild() != 0)
00323         {
00324           delete aNode->leftChild();
00325         }
00326 
00327       if (aNode->rightChild() != 0)
00328         {
00329           delete aNode->rightChild();
00330         }
00331 
00332       aNode->setLeftChild(0);
00333       aNode->setRightChild(0);
00334     }
00335 }
00336 
00337 
00338 // ADD A SEGMENT WHEN ON A TERMINAL NODE
00339 
00340 
00341 void
00342 RWSegmentVector::addSegmentIfTerminalNode(RWTree* aNode,
00343                                           vector<Point>& myChain)
00344 {
00345   if ((aNode->leftChild() != 0) || (aNode->rightChild() != 0))
00346     {
00347       if (aNode->leftChild() != 0)
00348         {
00349           addSegmentIfTerminalNode(aNode->leftChild(), myChain);
00350         }
00351 
00352       if (aNode->rightChild() != 0)
00353         {
00354           addSegmentIfTerminalNode(aNode->rightChild(), myChain);
00355         }
00356     }
00357   else
00358     {
00359       Segment newSeg(myChain[aNode->firstIdx()],
00360                      myChain[aNode->lastIdx()]);
00361       push_back(newSeg);
00362       _significance.push_back(aNode->significance());
00363       _indexes.push_back(aNode->firstIdx());
00364     }
00365 }
00366 
00367 
00368 // -------------------------------------------------------------------
00369 
00370 } // namespace qgar