openModeller  Version 1.4.0
Environment.cpp
Go to the documentation of this file.
00001 
00029 #include <openmodeller/Environment.hh>
00030 
00031 #include <openmodeller/os_specific.hh>
00032 #include <openmodeller/Log.hh>
00033 #include <openmodeller/env_io/Map.hh>
00034 #include <openmodeller/env_io/RasterFactory.hh>
00035 #include <openmodeller/env_io/GeoTransform.hh>
00036 #include <openmodeller/Random.hh>
00037 #include <openmodeller/Configuration.hh>
00038 #include <openmodeller/Occurrence.hh>
00039 #include <openmodeller/Exceptions.hh>
00040 
00041 #if defined (HAVE_VALUES_H) && !defined(WIN32)
00042 #include <values.h>
00043 #else
00044 #include <float.h>
00045 #define MAXFLOAT FLT_MAX
00046 #endif
00047 
00048 using std::string;
00049 using std::vector;
00050 
00051 #undef DEBUG_GET
00052 
00053 /****************************************************************/
00054 /*********************** factory methods ************************/
00055 EnvironmentPtr createEnvironment( const std::vector<std::string>& categs,
00056                                   const std::vector<std::string>& maps,
00057                                   const std::string& mask_file )
00058 {
00059   return EnvironmentPtr( new EnvironmentImpl( categs, maps, mask_file ) );
00060 }
00061 
00062 EnvironmentPtr createEnvironment( const std::vector<std::string>& categs,
00063                                   const std::vector<std::string>& maps )
00064 {
00065   return EnvironmentPtr( new EnvironmentImpl( categs, maps, "" ) );
00066 }
00067 
00068 EnvironmentPtr createEnvironment( const ConstConfigurationPtr& config )
00069 {
00070   EnvironmentPtr env( new EnvironmentImpl() );
00071 
00072   env->setConfiguration( config );
00073 
00074   return env;
00075 }
00076 
00077 EnvironmentPtr createEnvironment( )
00078 {
00079   return EnvironmentPtr( new EnvironmentImpl( ) );
00080 }
00081 
00082 
00083 /****************************************************************/
00084 /******************* static utility functions *******************/
00085 
00086 ConfigurationPtr
00087 EnvironmentImpl::getLayerConfig( const layer& l, bool basicConfig ) {
00088 
00089   ConfigurationPtr cfg( new ConfigurationImpl() );
00090 
00091   cfg->addNameValue( "Id", l.first );
00092 
00093   if ( ! basicConfig ) {
00094 
00095     cfg->addNameValue( "IsCategorical", l.second->isCategorical() );
00096 
00097     if ( l.second->hasMinMax() ) {
00098 
00099       Scalar min;
00100       Scalar max;
00101       l.second->getMinMax( &min, &max );
00102       cfg->addNameValue( "Min", min );
00103       cfg->addNameValue( "Max", max );
00104     }
00105   }
00106 
00107   return cfg;
00108 }
00109 
00110 EnvironmentImpl::layer
00111 EnvironmentImpl::makeLayer( const ConstConfigurationPtr& config, Map *map ) {
00112 
00113   string filename = config->getAttribute( "Id" );
00114   // map should already have the categorical attribute set!
00115   //int categ = config->getAttributeAsInt( "IsCategorical", 0 );
00116 
00117   layer l = makeLayer( filename, map );
00118 
00119   try {
00120 
00121     // The calls to getAttribute( string ) will throw if
00122     // the attribute is not found.
00123     config->getAttribute("Min");
00124     config->getAttribute("Max");
00125 
00126     // If we make it here, the attributes exist, and the
00127     // hard coded default value of 0.0 will not be used.
00128     double min = config->getAttributeAsDouble( "Min", 0.0 );
00129     double max = config->getAttributeAsDouble( "Max", 0.0 );
00130 
00131     l.second->setMinMax( min, max );
00132   }
00133   catch (AttributeNotFound& e) {
00134 
00135     UNUSED(e);
00136   }
00137 
00138   return l;
00139 }
00140 
00141 EnvironmentImpl::layer
00142 EnvironmentImpl::makeLayer( const string& filename, int categ ) {
00143 
00144   Map *map = new Map( RasterFactory::instance().create( filename, categ ) );
00145 
00146   return makeLayer( filename, map );
00147 }
00148 
00149 EnvironmentImpl::layer
00150 EnvironmentImpl::makeLayer( const string& filename, Map *map ) {
00151 
00152   layer l;
00153 
00154   if ( !map ) {
00155 
00156     Log::instance()->warn( "Cannot read environment file: '%s'\n", filename.c_str() );
00157   }
00158   else {
00159 
00160     l.first = filename;
00161     l.second = map;
00162   }
00163 
00164   return l;
00165 }
00166 
00167 
00168 /****************************************************************/
00169 /************************* EnvironmentImpl **************************/
00170 
00171 /*******************/
00172 /*** constructor ***/
00173 
00174 EnvironmentImpl::EnvironmentImpl() :
00175   _layers(),
00176   _mask(),
00177   _xmin(0),
00178   _ymin(0),
00179   _xmax(0),
00180   _ymax(0),
00181   _normalizerPtr(0)
00182 {
00183 }
00184 
00185 EnvironmentImpl::EnvironmentImpl( const std::vector<std::string>& categs,
00186           const std::vector<std::string>& maps, 
00187           const std::string& mask )
00188 {
00189   initialize( categs, maps, mask );
00190 }
00191 
00192 void
00193 EnvironmentImpl::initialize( const std::vector<std::string>& categs,
00194            const std::vector<std::string>& maps, 
00195            const std::string& mask )
00196 {
00197   _normalizerPtr = 0;
00198 
00199   // Initialize mask and read its region.
00200   changeMask( mask );
00201   changeLayers( categs, maps );
00202 }
00203 
00204 
00205 /******************/
00206 /*** destructor ***/
00207 
00208 EnvironmentImpl::~EnvironmentImpl()
00209 {
00210   clearLayers();
00211   clearMask();
00212 
00213   if ( _normalizerPtr ) {
00214 
00215     delete _normalizerPtr;
00216   }
00217 }
00218 
00219 
00220 /*****************/
00221 /*** deep copy ***/
00222 
00223 EnvironmentImpl*
00224 EnvironmentImpl::clone() const
00225 {
00226   std::vector<std::string> categs;
00227   std::vector<std::string> maps;
00228 
00229   layers::const_iterator lay = _layers.begin();
00230   layers::const_iterator end = _layers.end();
00231 
00232   while ( lay != end ) {
00233 
00234     if ( lay->second->isCategorical() ) {
00235 
00236       categs.push_back( lay->first );
00237     }
00238     else {
00239 
00240       maps.push_back( lay->first );
00241     }
00242 
00243     ++lay;
00244   }
00245 
00246   EnvironmentImpl* clone = new EnvironmentImpl( categs, maps, _mask.first );
00247 
00248   if ( _normalizerPtr ) {
00249 
00250     clone->normalize( _normalizerPtr );
00251   }
00252 
00253   return clone;
00254 }
00255 
00256 void
00257 EnvironmentImpl::clearLayers() {
00258   if (_layers.size() < 1) {
00259     return;
00260   }
00261   layers::iterator first = _layers.begin();
00262   layers::iterator end = _layers.end();
00263   for ( ; first != end; ++ first ) {
00264     delete (*first).second;
00265   }
00266   _layers.clear();
00267 }
00268 
00269 void
00270 EnvironmentImpl::clearMask() {
00271   if ( _mask.second )
00272     delete _mask.second;
00273 
00274   _mask.first = "";
00275   _mask.second = 0;
00276 }
00277 
00278 /*********************/
00279 /*** configuration ***/
00280 
00281 ConfigurationPtr
00282 EnvironmentImpl::getConfiguration() const
00283 {
00284   ConfigurationPtr config( new ConfigurationImpl("Environment") );
00285 
00286   config->addNameValue( "NumLayers", (int) _layers.size() );
00287 
00288   layers::const_iterator l = _layers.begin();
00289   layers::const_iterator end = _layers.end();
00290 
00291   for( ; l != end; ++l ) {
00292 
00293     ConfigurationPtr cfg( getLayerConfig( *l ) );
00294     cfg->setName("Map");
00295     config->addSubsection( cfg );
00296   }
00297 
00298   if ( _mask.second ) {
00299 
00300     bool onlyBasicConfig = true;
00301     ConfigurationPtr maskcfg( getLayerConfig( _mask, onlyBasicConfig ) );
00302     maskcfg->setName( "Mask" );
00303     config->addSubsection( maskcfg );
00304   }
00305 
00306   return config;
00307 }
00308 
00309 void
00310 EnvironmentImpl::setConfiguration( const ConstConfigurationPtr & config )
00311 {
00312   clearMask();
00313   clearLayers();
00314 
00315   // Store configuration references for each layer
00316   // Important: users can mix continuous and categorical layers, but oM
00317   //            requires categorical layers to be first, so having two
00318   //            vectors can handle this.
00319   std::vector<ConstConfigurationPtr> categ_layer_confs;
00320   std::vector<ConstConfigurationPtr> cont_layer_confs;
00321 
00322   // Need to have separate containers, since loadLayers requires
00323   // knowing if the layer is categorical or not.
00324   std::vector<string> categ_layer_ids;
00325   std::vector<Map*> categ_layer_refs;
00326   std::vector<string> cont_layer_ids;
00327   std::vector<Map*> cont_layer_refs;
00328 
00329   // Mask config
00330   ConstConfigurationPtr mask_conf = config->getSubsection( "Mask", false );
00331   std::vector<string> mask_id;
00332   std::vector<Map*> mask_ref;
00333 
00334   // Suck in all the filenames.
00335   Configuration::subsection_list subs = config->getAllSubsections();
00336   Configuration::subsection_list::const_iterator it = subs.begin();
00337   while( it != subs.end() ) {
00338 
00339     string subname = (*it)->getName();
00340     string id = (*it)->getAttribute("Id");
00341 
00342     if ( subname == "Mask" && mask_id.size() == 0 ) {
00343 
00344       // Mask
00345 
00346       mask_id.push_back(id);
00347       mask_ref.push_back(0);
00348     }
00349     else {
00350 
00351       // Environmental layer
00352 
00353       int categ = (*it)->getAttributeAsInt( "IsCategorical", 0 );
00354 
00355       if ( categ == 0 ) {
00356 
00357         cont_layer_ids.push_back(id);
00358         cont_layer_refs.push_back(0);
00359         const ConstConfigurationPtr lconf = (*it);
00360         cont_layer_confs.push_back(lconf);
00361       }
00362       else {
00363 
00364         categ_layer_ids.push_back(id);
00365         categ_layer_refs.push_back(0);
00366         const ConstConfigurationPtr lconf = (*it);
00367         categ_layer_confs.push_back(lconf);
00368       }
00369     }
00370 
00371     ++it;
00372   }
00373 
00374   loadLayers( categ_layer_ids, categ_layer_refs, 1 );
00375   loadLayers( cont_layer_ids, cont_layer_refs, 0 );
00376 
00377   // Fill _layers attribute
00378   for( unsigned int i = 0; i< categ_layer_confs.size(); i++ ) {
00379 
00380     // Call makeLayer with the config object! This implementation is more complete
00381     // than just calling it with id and categorical attributes.
00382     _layers.push_back( makeLayer( categ_layer_confs[i], categ_layer_refs[i] ) );
00383   }
00384 
00385   for( unsigned int i = 0; i< cont_layer_confs.size(); i++ ) {
00386 
00387     // Call makeLayer with the config object! This implementation is more complete
00388     // than just calling it with id and categorical attributes.
00389     _layers.push_back( makeLayer( cont_layer_confs[i], cont_layer_refs[i] ) );
00390   }
00391 
00392   // Assign mask
00393   if ( mask_id.size() ) {
00394 
00395     loadLayers( mask_id, mask_ref, 0 );
00396     _mask = makeLayer( mask_conf, mask_ref[0] );
00397   }
00398 
00399   calcRegion();
00400 }
00401 
00402 /*******************/
00403 /*** load Layers ***/
00404 void
00405 EnvironmentImpl::loadLayers( const std::vector<string>& map_ids, std::vector<Map*>& map_refs, int categ )
00406 {
00407   bool unfinished_loading = true;
00408   bool got_one = false;
00409 
00410   while ( unfinished_loading ) {
00411 
00412     unfinished_loading = false;
00413     got_one = false;
00414 
00415     for( unsigned int i = 0; i< map_ids.size(); i++ ) {
00416 
00417       if ( map_refs[i] == 0 ) {
00418 
00419         try {
00420 
00421           map_refs[i] = new Map( RasterFactory::instance().create( map_ids[i], categ ) );
00422           got_one = true;
00423         }
00424         catch ( RasterException& e ) {
00425 
00426           if ( e.getCode() == 1 ) {
00427 
00428             // layer is being downloaded by other process, 
00429             // so skip it for now and try others
00430             unfinished_loading = true;
00431           }
00432           else {
00433 
00434             throw;
00435           }
00436         }
00437       }
00438     }
00439 
00440     if ( unfinished_loading && !got_one ) {
00441 
00442       Sleep(5000);
00443     }
00444   }
00445 }
00446 
00447 /*********************/
00448 /*** change Layers ***/
00449 int
00450 EnvironmentImpl::changeLayers( const std::vector<std::string>& categs,
00451              const std::vector<std::string>& maps )
00452 {
00453   if ( ! (categs.size() + maps.size()) )
00454     return 0;
00455 
00456   clearLayers();
00457 
00458   // STL maps with layer ids (unique) pointing to Map*s
00459 
00460   // categorical data
00461   std::vector<Map*> categ_layer_refs;
00462   for( unsigned int i = 0; i< categs.size(); i++ ) {
00463 
00464     categ_layer_refs.push_back(0);
00465   }
00466 
00467   loadLayers( categs, categ_layer_refs, 1 );
00468 
00469   // continuous data
00470   std::vector<Map*> cont_layer_refs;
00471   for( unsigned int i = 0; i< maps.size(); i++ ) {
00472 
00473     cont_layer_refs.push_back(0);
00474   }
00475 
00476   loadLayers( maps, cont_layer_refs, 0 );
00477 
00478   // Fill _layers attribute
00479   for( unsigned int i = 0; i< categs.size(); i++ ) {
00480 
00481     _layers.push_back( makeLayer(categs[i], categ_layer_refs[i]) );
00482   }
00483 
00484   for( unsigned int i = 0; i< maps.size(); i++ ) {
00485 
00486     _layers.push_back( makeLayer(maps[i], cont_layer_refs[i]) );
00487   }
00488 
00489   calcRegion();
00490 
00491   return categs.size() + maps.size();
00492 }
00493 
00494 
00495 /*******************/
00496 /*** change Mask ***/
00497 int
00498 EnvironmentImpl::changeMask( const std::string& mask_file )
00499 {
00500   int ret = 1;
00501 
00502   clearMask();
00503 
00504   // New mask
00505   if ( !mask_file.empty() ) {
00506 
00507     bool unfinished_loading = true;
00508   
00509     while ( unfinished_loading ) {
00510 
00511       unfinished_loading = false;
00512 
00513       try {
00514 
00515         _mask = makeLayer( mask_file, 0 );
00516       }
00517       catch ( RasterException& e ) {
00518 
00519         if ( e.getCode() == 1 ) {
00520 
00521           // mask is being downloaded by other process
00522           unfinished_loading = true;
00523           Sleep(5000);
00524         }
00525         else {
00526 
00527           throw;
00528         }
00529       }
00530     }
00531 
00532     if ( !_mask.second ) {
00533 
00534       ret = 0;
00535     }
00536   }
00537 
00538   calcRegion();
00539 
00540   return ret;
00541 }
00542 
00543 
00544 /******************************/
00545 /*** num Categorical Layers ***/
00546 size_t
00547 EnvironmentImpl::numCategoricalLayers() const
00548 {
00549   size_t size = 0;
00550 
00551   layers::const_iterator lay = _layers.begin();
00552   layers::const_iterator end = _layers.end();
00553 
00554   while ( lay != end && lay->second->isCategorical() ) {
00555 
00556     ++size;
00557     ++lay;
00558   }
00559 
00560   return size;
00561 }
00562 
00563 
00564 /*****************/
00565 /*** get Type ***/
00566 int
00567 EnvironmentImpl::isCategorical( int i )
00568 {
00569   return _layers[i].second->isCategorical();
00570 }
00571 
00572 
00573 /******************/
00574 /*** get MinMax ***/
00575 void 
00576 EnvironmentImpl::getMinMax( Sample * min, Sample * max ) const
00577 {
00578   int i = 0;
00579 
00580   layers::const_iterator lay = _layers.begin();
00581   layers::const_iterator end = _layers.end();
00582 
00583   while ( lay != end ) {
00584 
00585     Map *map = lay->second;
00586 
00587     Scalar mapMin, mapMax;
00588     map->getMinMax( &mapMin, &mapMax );
00589     (*min)[i] = mapMin;
00590     (*max)[i] = mapMax;
00591 
00592     ++lay;
00593     i++;
00594   }
00595 }
00596 
00597 /*****************/
00598 /*** normalize ***/
00599 void
00600 EnvironmentImpl::normalize( Normalizer * normalizerPtr ) {
00601 
00602   if ( normalizerPtr ) {
00603 
00604     _normalizerPtr = normalizerPtr->getCopy();
00605   }
00606   else {
00607 
00608     resetNormalization();
00609   }
00610 }
00611 
00612 
00613 /***************************/
00614 /*** reset Normalization ***/
00615 void
00616 EnvironmentImpl::resetNormalization() {
00617 
00618   if ( _normalizerPtr ) {
00619 
00620     delete _normalizerPtr;
00621 
00622     _normalizerPtr = 0;
00623   }
00624 }
00625 
00626 /*********************************/
00627 /*** get Unnormalized Internal ***/
00628 void
00629 EnvironmentImpl::getUnnormalizedInternal( Sample *sample, Coord x, Coord y ) const
00630 {
00631   // layers and the mask, if possible.
00632   if ( ! checkCoordinates( x, y ) ) {
00633 #if defined(DEBUG_GET)
00634     Log::instance()->debug( "EnvironmentImpl::get() Coordinate (%f,%f) is not in common region\n",x,y);
00635 #endif
00636     return;
00637   }
00638 
00639   // Create the return value.
00640   sample->resize( _layers.size() );
00641 
00642   // Read variables values from the layers.
00643   layers::const_iterator lay = _layers.begin();
00644   layers::const_iterator end = _layers.end();
00645   Sample::iterator s = sample->begin();
00646 
00647   while ( lay != end ) {
00648 
00649     if ( ! lay->second->get( x, y, s ) ) {
00650 #if defined(DEBUG_GET)
00651       Log::instance()->debug( "EnvironmentImpl::get() Coordinate (%f,%f) does not have data in layer %s\n",x,y,lay->first.c_str());
00652 #endif
00653       sample->resize(0);
00654       return;
00655     }
00656     ++lay;
00657     ++s;
00658   }
00659 }
00660 
00661 Sample
00662 EnvironmentImpl::getUnnormalized( Coord x, Coord y ) const
00663 {
00664   Sample sample;
00665   getUnnormalizedInternal( &sample, x, y );
00666   return sample;
00667 }
00668 
00669 Sample
00670 EnvironmentImpl::getNormalized( Coord x, Coord y ) const
00671 {
00672   Sample sample;
00673   getUnnormalizedInternal( &sample, x, y);
00674 
00675   sample.setCategoricalThreshold( numCategoricalLayers() );
00676 
00677   if ( _normalizerPtr ) {
00678 
00679     _normalizerPtr->normalize( &sample );
00680   }
00681 
00682   return sample;
00683 }
00684 
00685 Sample
00686 EnvironmentImpl::get( Coord x, Coord y ) const
00687 {
00688   if ( _normalizerPtr ) {
00689 
00690     return getNormalized(x,y);
00691   }
00692   else {
00693 
00694     return getUnnormalized(x,y);
00695   }
00696 }
00697 
00698 Sample
00699 EnvironmentImpl::getRandom( Coord *xout, Coord *yout ) const
00700 {
00701   Random myrand;
00702   Coord x, y;
00703 
00704   Sample s;
00705 
00706   int max_loop = 5000;
00707 
00708   int loop = 0;
00709 
00710   do {
00711 
00712     x = myrand( _xmin, _xmax );
00713     y = myrand( _ymin, _ymax );
00714 
00715     s = get( x, y );
00716 
00717     loop++;
00718 
00719   } while ( s.size() == 0 && loop < max_loop );
00720 
00721   if ( loop == max_loop ) {
00722 
00723     std::string msg = "Exceeded maximum number of attempts to generate pseudo point.\n";
00724 
00725     Log::instance()->error( msg.c_str() );
00726 
00727     throw OmException( msg );
00728   }
00729 
00730   if ( xout != 0 )
00731     *xout = x;
00732   if ( yout != 0 )
00733     *yout = y;
00734 
00735   return s;
00736 }
00737 
00738 
00739 /*************************/
00740 /*** check Coordinates ***/
00741 int
00742 EnvironmentImpl::checkCoordinates( Coord x, Coord y ) const
00743 {
00744   // Accept the point, regardless of mask, if
00745   // it falls in a common region among all layers.
00746   if ( x < _xmin || x > _xmax || y < _ymin || y > _ymax ) {
00747 #if defined(DEBUG_GET)
00748     Log::instance()->debug( "EnvironmentImpl::checkCoordinates() Coordinate (%f,%f) not in extent of all regions\n",x,y);
00749 #endif
00750 
00751     return 0;
00752   }
00753 
00754   // If there's no mask, accept the point.
00755   if ( ! _mask.second ) {
00756 
00757     return 1;
00758   }
00759 
00760   Scalar val;
00761 
00762   bool hasmaskevalue = ( _mask.second->get( x, y, &val ) > 0 );
00763 
00764   if ( ! hasmaskevalue ) {
00765 #if defined(DEBUG_GET)
00766     Log::instance()->debug( "EnvironmentImpl::check() Coordinate (%f,%f) has no mask value\n",x,y);
00767 #endif
00768   }
00769 
00770   return hasmaskevalue;
00771 }
00772 
00773 
00774 /******************/
00775 /*** get Region ***/
00776 int
00777 EnvironmentImpl::getRegion( Coord *xmin, Coord *ymin, Coord *xmax, Coord *ymax ) const
00778 {
00779   *xmin = _xmin;
00780   *ymin = _ymin;
00781   *xmax = _xmax;
00782   *ymax = _ymax;
00783 
00784   return 1;
00785 }
00786 
00787 int
00788 EnvironmentImpl::getExtremes( Sample* min, Sample* max ) const
00789 {
00790   int nlayers = _layers.size();
00791   min->resize( nlayers );
00792   max->resize( nlayers );
00793 
00794   layers::const_iterator map = _layers.begin();
00795 
00796   for ( int i = 0; i < nlayers; i++  ) {
00797     Scalar amin, amax;
00798     map->second->getMinMax( &amin, &amax );
00799     (*min)[i] = amin;
00800     (*max)[i] = amax;
00801     ++map;
00802   }
00803 
00804   if ( _normalizerPtr ) {
00805 
00806     _normalizerPtr->normalize( min );
00807     _normalizerPtr->normalize( max );
00808   }
00809 
00810   return 1;
00811 }
00812 
00813 
00814 /*******************/
00815 /*** calc Region ***/
00816 void
00817 EnvironmentImpl::calcRegion()
00818 {
00819   Coord xmin, ymin, xmax, ymax;
00820 
00821   _xmin = _ymin = -MAXFLOAT;
00822   _xmax = _ymax =  MAXFLOAT;
00823 
00824   // The mask region is the default.
00825   if ( _mask.second )
00826     _mask.second->getExtent( &_xmin, &_ymin, &_xmax, &_ymax );
00827 
00828   // Crop region to fit all layers.
00829   layers::const_iterator lay = _layers.begin();
00830   layers::const_iterator end = _layers.end();
00831   while ( lay != end ) {
00832     lay->second->getExtent( &xmin, &ymin, &xmax, &ymax );
00833     ++lay;
00834 
00835     if ( xmin > _xmin )
00836       _xmin = xmin;
00837     
00838     if ( ymin > _ymin )
00839       _ymin = ymin;
00840     
00841     if ( xmax < _xmax )
00842       _xmax = xmax;
00843     
00844     if ( ymax < _ymax )
00845       _ymax = ymax;
00846   }
00847 
00848   if ( (_xmin >= _xmax)  || ( _ymin >= _ymax ) ) {
00849     Log::instance()->warn( "Maps intersection is empty (boundaries: xmin=%f, xmax=%f, ymin=%f, ymax=%f)\n", _xmin, _xmax, _ymin, _ymax );
00850   }
00851 }
00852 
00853 
00854 /********************/
00855 /*** remove Layer ***/
00856 void
00857 EnvironmentImpl::removeLayer(unsigned int index)
00858 {
00859   if ( index >= numLayers() ) {
00860 
00861     return;
00862   }
00863 
00864   layers::iterator it = _layers.begin();
00865 
00866   unsigned int tmp = 0;
00867 
00868   while ( tmp < index ) {
00869 
00870     ++tmp;
00871     ++it;
00872   }
00873 
00874   _layers.erase( it );
00875 
00876   calcRegion();
00877 }