osgEarth 2.1.1
|
00001 /* -*-c++-*- */ 00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00003 * Copyright 2008-2010 Pelican Mapping 00004 * http://osgearth.org 00005 * 00006 * osgEarth is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 00018 */ 00019 #include <osgEarthFeatures/FeatureGridder> 00020 #include <osgEarthSymbology/Geometry> 00021 #include <osg/Notify> 00022 #include <osg/Timer> 00023 00024 #define LC "[FeatureGridder] " 00025 00026 using namespace osgEarth; 00027 using namespace osgEarth::Features; 00028 00029 /**************************************************************************/ 00030 00031 #define PROP_CELL_SIZE "cell_size" 00032 #define PROP_CULLING_TECHNIQUE "culling_technique" 00033 #define PROP_SPATIALIZE_GROUPS "spatialize_groups" 00034 #define PROP_CLUSTER_CULLING "cluster_culling" 00035 00036 GriddingPolicy::GriddingPolicy( const Config& conf ) : 00037 _cellSize( DBL_MAX ), 00038 _cullingTechnique( GriddingPolicy::CULL_BY_CENTROID ), 00039 _spatializeGroups( true ), 00040 _clusterCulling( false ) 00041 { 00042 fromConfig( conf ); 00043 } 00044 00045 Config 00046 GriddingPolicy::getConfig() const 00047 { 00048 Config conf; 00049 00050 conf.updateIfSet( PROP_CELL_SIZE, _cellSize ); 00051 00052 if ( _cullingTechnique.isSet() ) { 00053 if ( _cullingTechnique == CULL_BY_CROPPING ) 00054 conf.update( PROP_CULLING_TECHNIQUE, "crop" ); 00055 else if ( _cullingTechnique == CULL_BY_CENTROID ) 00056 conf.update( PROP_CULLING_TECHNIQUE, "centroid" ); 00057 } 00058 00059 conf.updateIfSet( PROP_SPATIALIZE_GROUPS, _spatializeGroups ); 00060 conf.updateIfSet( PROP_CLUSTER_CULLING, _clusterCulling ); 00061 00062 return conf; 00063 } 00064 00065 void 00066 GriddingPolicy::fromConfig( const Config& conf ) 00067 { 00068 conf.getIfSet( PROP_CELL_SIZE, _cellSize ); 00069 00070 // read the culling technique 00071 if ( conf.hasValue( PROP_CULLING_TECHNIQUE ) ) { 00072 if ( conf.value( PROP_CULLING_TECHNIQUE ) == "crop" ) 00073 _cullingTechnique = CULL_BY_CROPPING; 00074 else if ( conf.value( PROP_CULLING_TECHNIQUE ) == "centroid" ) 00075 _cullingTechnique = CULL_BY_CENTROID; 00076 } 00077 00078 // spatial optimization 00079 conf.getIfSet<bool>( PROP_SPATIALIZE_GROUPS, _spatializeGroups ); 00080 00081 // cluster culling 00082 conf.getIfSet<bool>( PROP_CLUSTER_CULLING, _clusterCulling ); 00083 } 00084 00085 /***************************************************************************/ 00086 00087 FeatureGridder::FeatureGridder(const Bounds& inputBounds, 00088 const GriddingPolicy& policy ) : 00089 _inputBounds( inputBounds ), 00090 _policy( policy ) 00091 { 00092 if ( _policy.enabled() ) //_policy.cellSize().isSet() && *_policy.cellSize() > 0.0 ) 00093 { 00094 _cellsX = (int)::ceil(_inputBounds.width() / *_policy.cellSize() ); 00095 _cellsY = (int)::ceil(_inputBounds.height() / *_policy.cellSize() ); 00096 } 00097 else 00098 { 00099 _cellsX = 1; 00100 _cellsY = 1; 00101 } 00102 00103 _cellsX = osg::clampAbove( _cellsX, 1 ); 00104 _cellsY = osg::clampAbove( _cellsY, 1 ); 00105 00106 #ifndef OSGEARTH_HAVE_GEOS 00107 00108 if ( _policy.cullingTechnique().isSetTo( GriddingPolicy::CULL_BY_CROPPING ) ) 00109 { 00110 OE_WARN 00111 << "Warning: Gridding policy 'cull by cropping' requires GEOS. Falling back on 'cull by centroid'." 00112 << std::endl; 00113 00114 _policy.cullingTechnique() = GriddingPolicy::CULL_BY_CENTROID; 00115 } 00116 00117 #endif // !OSGEARTH_HAVE_GEOS 00118 } 00119 00120 FeatureGridder::~FeatureGridder() 00121 { 00122 //nop 00123 } 00124 00125 int 00126 FeatureGridder::getNumCells() const 00127 { 00128 return _cellsX * _cellsY; 00129 } 00130 00131 bool 00132 FeatureGridder::getCellBounds( int i, Bounds& output ) const 00133 { 00134 if ( i >= 0 && i < (_cellsX*_cellsY) ) 00135 { 00136 int x = i % _cellsX; 00137 int y = i / _cellsX; 00138 00139 double xmin = _inputBounds.xMin() + _policy.cellSize().value() * (double)x; 00140 double ymin = _inputBounds.yMin() + _policy.cellSize().value() * (double)y; 00141 double xmax = osg::clampBelow( _inputBounds.xMin() + *_policy.cellSize() * (double)(x+1), _inputBounds.xMax() ); 00142 double ymax = osg::clampBelow( _inputBounds.yMin() + *_policy.cellSize() * (double)(y+1), _inputBounds.yMax() ); 00143 00144 output = Bounds( xmin, ymin, xmax, ymax ); 00145 return true; 00146 } 00147 return false; 00148 } 00149 00150 bool 00151 FeatureGridder::cullFeatureListToCell( int i, FeatureList& features ) const 00152 { 00153 bool success = true; 00154 int inCount = features.size(); 00155 00156 Bounds b; 00157 if ( getCellBounds( i, b ) ) 00158 { 00159 if ( _policy.cullingTechnique() == GriddingPolicy::CULL_BY_CENTROID ) 00160 { 00161 for( FeatureList::iterator f_i = features.begin(); f_i != features.end(); ) 00162 { 00163 bool keepFeature = false; 00164 00165 Feature* feature = f_i->get(); 00166 Symbology::Geometry* featureGeom = feature->getGeometry(); 00167 if ( featureGeom ) 00168 { 00169 osg::Vec3d centroid = featureGeom->getBounds().center(); 00170 if ( b.contains( centroid.x(), centroid.y() ) ) 00171 { 00172 keepFeature = true; 00173 } 00174 } 00175 00176 if ( keepFeature ) 00177 ++f_i; 00178 else 00179 f_i = features.erase( f_i ); 00180 } 00181 } 00182 00183 else // CULL_BY_CROPPING (requires GEOS) 00184 { 00185 00186 #ifdef OSGEARTH_HAVE_GEOS 00187 00188 // create the intersection polygon: 00189 osg::ref_ptr<Symbology::Polygon> poly = new Symbology::Polygon( 4 ); 00190 poly->push_back( osg::Vec3d( b.xMin(), b.yMin(), 0 )); 00191 poly->push_back( osg::Vec3d( b.xMax(), b.yMin(), 0 )); 00192 poly->push_back( osg::Vec3d( b.xMax(), b.yMax(), 0 )); 00193 poly->push_back( osg::Vec3d( b.xMin(), b.yMax(), 0 )); 00194 00195 for( FeatureList::iterator f_i = features.begin(); f_i != features.end(); ) 00196 { 00197 bool keepFeature = false; 00198 00199 Feature* feature = f_i->get(); 00200 Symbology::Geometry* featureGeom = feature->getGeometry(); 00201 if ( featureGeom ) 00202 { 00203 osg::ref_ptr<Symbology::Geometry> croppedGeometry; 00204 if ( featureGeom->crop( poly.get(), croppedGeometry ) ) 00205 { 00206 feature->setGeometry( croppedGeometry.get() ); 00207 keepFeature = true; 00208 } 00209 } 00210 00211 if ( keepFeature ) 00212 ++f_i; 00213 else 00214 f_i = features.erase( f_i ); 00215 } 00216 00217 #endif // OSGEARTH_HAVE_GEOS 00218 00219 } 00220 00221 } 00222 00223 OE_INFO << LC 00224 << "Grid cell " << i << ": bounds=" 00225 << b.xMin() << "," << b.yMin() << " => " << b.xMax() << "," << b.yMax() 00226 << "; in=" << inCount << "; out=" << features.size() 00227 << std::endl; 00228 00229 return success; 00230 } 00231