void Map::addModelLayer( ModelLayer* layer ) { if ( layer ) { unsigned int index = -1; Revision newRevision; { Threading::ScopedWriteLock lock( _mapDataMutex ); _modelLayers.push_back( layer ); index = _modelLayers.size() - 1; newRevision = ++_dataModelRevision; } // initialize the model layer layer->initialize( _dbOptions.get() ); // a seprate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::ADD_MODEL_LAYER, newRevision, layer, index ) ); } } }
void Map::removeImageLayer( ImageLayer* layer ) { osgEarth::Registry::instance()->clearBlacklist(); unsigned int index = -1; osg::ref_ptr<ImageLayer> layerToRemove = layer; Revision newRevision; if ( layerToRemove.get() ) { Threading::ScopedWriteLock lock( _mapDataMutex ); index = 0; for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end(); i++, index++ ) { if ( i->get() == layerToRemove.get() ) { _imageLayers.erase( i ); newRevision = ++_dataModelRevision; break; } } } // a separate block b/c we don't need the mutex if ( newRevision >= 0 ) // layerToRemove.get() ) { for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::REMOVE_IMAGE_LAYER, newRevision, layerToRemove.get(), index) ); //i->get()->onImageLayerRemoved( layerToRemove.get(), index, newRevision ); } } }
void Map::removeTerrainMaskLayer( MaskLayer* layer ) { if ( layer ) { //Take a reference to the layer since we will be deleting it osg::ref_ptr< MaskLayer > layerRef = layer; Revision newRevision; { Threading::ScopedWriteLock lock( _mapDataMutex ); for( MaskLayerVector::iterator i = _terrainMaskLayers.begin(); i != _terrainMaskLayers.end(); ++i ) { if ( i->get() == layer ) { _terrainMaskLayers.erase( i ); newRevision = ++_dataModelRevision; break; } } } // a separate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::REMOVE_MASK_LAYER, newRevision, layerRef.get()) ); } } }
void Map::endUpdate() { MapModelChange msg( MapModelChange::END_BATCH_UPDATE, _dataModelRevision ); for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( msg ); } }
void Map::clear() { ImageLayerVector imageLayersRemoved; ElevationLayerVector elevLayersRemoved; ModelLayerVector modelLayersRemoved; MaskLayerVector maskLayersRemoved; Revision newRevision; { Threading::ScopedWriteLock lock( _mapDataMutex ); imageLayersRemoved.swap( _imageLayers ); elevLayersRemoved.swap ( _elevationLayers ); modelLayersRemoved.swap( _modelLayers ); // Because you cannot remove a mask layer once it's in place //maskLayersRemoved.swap ( _terrainMaskLayers ); // calculate a new revision. newRevision = ++_dataModelRevision; } // a separate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { for( ImageLayerVector::iterator k = imageLayersRemoved.begin(); k != imageLayersRemoved.end(); ++k ) i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_IMAGE_LAYER, newRevision, k->get()) ); for( ElevationLayerVector::iterator k = elevLayersRemoved.begin(); k != elevLayersRemoved.end(); ++k ) i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_ELEVATION_LAYER, newRevision, k->get()) ); for( ModelLayerVector::iterator k = modelLayersRemoved.begin(); k != modelLayersRemoved.end(); ++k ) i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_MODEL_LAYER, newRevision, k->get()) ); //for( MaskLayerVector::iterator k = maskLayersRemoved.begin(); k != maskLayersRemoved.end(); ++k ) // i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_MASK_LAYER, newRevision, k->get()) ); } }
void Map::moveModelLayer( ModelLayer* layer, unsigned int newIndex ) { unsigned int oldIndex = 0; unsigned int actualIndex = 0; Revision newRevision; if ( layer ) { Threading::ScopedWriteLock lock( _mapDataMutex ); // preserve the layer with a ref: osg::ref_ptr<ModelLayer> layerToMove = layer; // find it: ModelLayerVector::iterator i_oldIndex = _modelLayers.end(); for( ModelLayerVector::iterator i = _modelLayers.begin(); i != _modelLayers.end(); i++, actualIndex++ ) { if ( i->get() == layer ) { i_oldIndex = i; oldIndex = actualIndex; break; } } if ( i_oldIndex == _modelLayers.end() ) return; // layer not found in list // erase the old one and insert the new one. _modelLayers.erase( i_oldIndex ); _modelLayers.insert( _modelLayers.begin() + newIndex, layerToMove.get() ); newRevision = ++_dataModelRevision; } // a separate block b/c we don't need the mutex if ( layer ) { for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::MOVE_MODEL_LAYER, newRevision, layer, oldIndex, newIndex) ); } } }
void Map::notifyElevationLayerVisibleChanged(TerrainLayer* layer) { // bump the revision safely: Revision newRevision; { Threading::ScopedWriteLock lock( const_cast<Map*>(this)->_mapDataMutex ); newRevision = ++_dataModelRevision; } // a separate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::TOGGLE_ELEVATION_LAYER, newRevision, layer) ); } }
void Map::insertImageLayer( ImageLayer* layer, unsigned int index ) { osgEarth::Registry::instance()->clearBlacklist(); if ( layer ) { //Set options for the map from the layer layer->setDBOptions( _dbOptions.get() ); //propagate the cache to the layer: if (_mapOptions.cachePolicy().isSet() ) { layer->overrideCachePolicy( *_mapOptions.cachePolicy() ); } //Set the Cache for the MapLayer to our cache. layer->setCache( this->getCache() ); // Tell the layer the map profile, if possible: if ( _profile.valid() ) layer->setTargetProfileHint( _profile.get() ); int newRevision; // Add the layer to our stack. { Threading::ScopedWriteLock lock( _mapDataMutex ); if (index >= _imageLayers.size()) _imageLayers.push_back(layer); else _imageLayers.insert( _imageLayers.begin() + index, layer ); newRevision = ++_dataModelRevision; } // a separate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::ADD_IMAGE_LAYER, newRevision, layer, index) ); } } }
void Map::addImageLayer( ImageLayer* layer ) { unsigned int index = -1; if ( layer ) { //Set options for the map from the layer layer->setReferenceURI( _mapOptions.referenceURI().value() ); //propagate the cache to the layer: if ( _mapOptions.cache().isSet() && _mapOptions.cache()->cacheOnly().isSetTo( true ) ) { layer->setCacheOnly( true ); } //Set the Cache for the MapLayer to our cache. layer->setCache( this->getCache() ); // Tell the layer the map profile, if possible: if ( _profile.valid() ) layer->setTargetProfileHint( _profile.get() ); int newRevision; // Add the layer to our stack. { Threading::ScopedWriteLock lock( _mapDataMutex ); _imageLayers.push_back( layer ); index = _imageLayers.size() - 1; newRevision = ++_dataModelRevision; } // a separate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::ADD_IMAGE_LAYER, newRevision, layer, index) ); //i->get()->onImageLayerAdded( layer, index, newRevision ); } } }
void Map::addTerrainMaskLayer( MaskLayer* layer ) { if ( layer ) { Revision newRevision; { Threading::ScopedWriteLock lock( _mapDataMutex ); _terrainMaskLayers.push_back(layer); newRevision = ++_dataModelRevision; } layer->initialize( _dbOptions.get(), this ); // a separate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::ADD_MASK_LAYER, newRevision, layer) ); } } }
void Map::addElevationLayer( ElevationLayer* layer ) { osgEarth::Registry::instance()->clearBlacklist(); unsigned int index = -1; if ( layer ) { //Set options for the map from the layer layer->setDBOptions( _dbOptions.get() ); //Set the Cache for the MapLayer to our cache. layer->setCache( this->getCache() ); // Tell the layer the map profile, if possible: if ( _profile.valid() ) layer->setTargetProfileHint( _profile.get() ); int newRevision; // Add the layer to our stack. { Threading::ScopedWriteLock lock( _mapDataMutex ); _elevationLayers.push_back( layer ); index = _elevationLayers.size() - 1; newRevision = ++_dataModelRevision; } // listen for changes in the layer. layer->addCallback( _elevationLayerCB.get() ); // a separate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::ADD_ELEVATION_LAYER, newRevision, layer, index) ); } } }
void Map::insertModelLayer( ModelLayer* layer, unsigned int index ) { if ( layer ) { Revision newRevision; { Threading::ScopedWriteLock lock( _mapDataMutex ); _modelLayers.insert( _modelLayers.begin() + index, layer ); newRevision = ++_dataModelRevision; } layer->initialize( _mapOptions.referenceURI().get(), this ); //getReferenceURI(), this ); // a seprate block b/c we don't need the mutex for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapModelChanged( MapModelChange( MapModelChange::ADD_MODEL_LAYER, newRevision, layer, index) ); } } }
void Map::calculateProfile() { if ( !_profile.valid() ) { osg::ref_ptr<const Profile> userProfile; if ( _mapOptions.profile().isSet() ) { userProfile = Profile::create( _mapOptions.profile().value() ); } if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC ) { if ( userProfile.valid() ) { if ( userProfile->isOK() && userProfile->getSRS()->isGeographic() ) { _profile = userProfile.get(); } else { OE_WARN << LC << "Map is geocentric, but the configured profile SRS (" << userProfile->getSRS()->getName() << ") is not geographic; " << "it will be ignored." << std::endl; } } if ( !_profile.valid() ) { // by default, set a geocentric map to use global-geodetic WGS84. _profile = osgEarth::Registry::instance()->getGlobalGeodeticProfile(); } } else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE ) { //If the map type is a Geocentric Cube, set the profile to the cube profile. _profile = osgEarth::Registry::instance()->getCubeProfile(); } else // CSTYPE_PROJECTED { if ( userProfile.valid() ) { _profile = userProfile.get(); } } // At this point, if we don't have a profile we need to search tile sources until we find one. if ( !_profile.valid() ) { Threading::ScopedReadLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end() && !_profile.valid(); i++ ) { ImageLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end() && !_profile.valid(); i++ ) { ElevationLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } } // convert the profile to Plate Carre if necessary. if (_profile.valid() && _profile->getSRS()->isGeographic() && getMapOptions().coordSysType() == MapOptions::CSTYPE_PROJECTED ) { OE_INFO << LC << "Projected display with geographic SRS; activating Plate Carre mode" << std::endl; _profile = _profile->overrideSRS( _profile->getSRS()->createPlateCarreGeographicSRS() ); } // finally, fire an event if the profile has been set. if ( _profile.valid() ) { OE_INFO << LC << "Map profile is: " << _profile->toString() << std::endl; for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapInfoEstablished( MapInfo(this) ); } } else { OE_WARN << LC << "Warning, not yet able to establish a map profile!" << std::endl; } } if ( _profile.valid() ) { // tell all the loaded layers what the profile is, as a hint { Threading::ScopedWriteLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end(); i++ ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() == true ) { layer->setTargetProfileHint( _profile.get() ); } } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end(); i++ ) { ElevationLayer* layer = i->get(); if ( layer->getEnabled() ) { layer->setTargetProfileHint( _profile.get() ); } } } // create a "proxy" profile to use when querying elevation layers with a vertical datum if ( _profile->getSRS()->getVerticalDatum() != 0L ) { ProfileOptions po = _profile->toProfileOptions(); po.vsrsString().unset(); _profileNoVDatum = Profile::create(po); } else { _profileNoVDatum = _profile; } } }
void Map::calculateProfile() { if ( !_profile.valid() ) { osg::ref_ptr<const Profile> userProfile; if ( _mapOptions.profile().isSet() ) { userProfile = Profile::create( _mapOptions.profile().value() ); } if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC ) { if ( userProfile.valid() ) { if ( userProfile->isOK() && userProfile->getSRS()->isGeographic() ) { _profile = userProfile.get(); } else { OE_WARN << LC << "Map is geocentric, but the configured profile does not " << "have a geographic SRS. Falling back on default.." << std::endl; } } if ( !_profile.valid() ) { // by default, set a geocentric map to use global-geodetic WGS84. _profile = osgEarth::Registry::instance()->getGlobalGeodeticProfile(); } } else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE ) { //If the map type is a Geocentric Cube, set the profile to the cube profile. _profile = osgEarth::Registry::instance()->getCubeProfile(); } else // CSTYPE_PROJECTED { if ( userProfile.valid() ) { _profile = userProfile.get(); } } // At this point, if we don't have a profile we need to search tile sources until we find one. if ( !_profile.valid() ) { Threading::ScopedReadLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end() && !_profile.valid(); i++ ) { ImageLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end() && !_profile.valid(); i++ ) { ElevationLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } } // finally, fire an event if the profile has been set. if ( _profile.valid() ) { OE_INFO << LC << "Map profile is: " << _profile->toString() << std::endl; for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapInfoEstablished( MapInfo(this) ); } } else { OE_WARN << LC << "Warning, not yet able to establish a map profile!" << std::endl; } } if ( _profile.valid() ) { // tell all the loaded layers what the profile is, as a hint { Threading::ScopedWriteLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end(); i++ ) { ImageLayer* layer = i->get(); layer->setTargetProfileHint( _profile.get() ); } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end(); i++ ) { ElevationLayer* layer = i->get(); layer->setTargetProfileHint( _profile.get() ); } } } }