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/AltitudeFilter> 00020 #include <osgEarth/ElevationQuery> 00021 #include <osgEarth/GeoData> 00022 00023 #define LC "[AltitudeFilter] " 00024 00025 using namespace osgEarth; 00026 using namespace osgEarth::Features; 00027 using namespace osgEarth::Symbology; 00028 00029 //--------------------------------------------------------------------------- 00030 00031 AltitudeFilter::AltitudeFilter() : 00032 _maxRes ( 0.0f ) 00033 { 00034 //NOP 00035 } 00036 00037 void 00038 AltitudeFilter::setPropertiesFromStyle( const Style& style ) 00039 { 00040 _altitude = style.get<AltitudeSymbol>(); 00041 if ( _altitude ) 00042 { 00043 setMaxResolution( *_altitude->clampingResolution() ); 00044 } 00045 } 00046 00047 FilterContext 00048 AltitudeFilter::push( FeatureList& features, FilterContext& cx ) 00049 { 00050 const Session* session = cx.getSession(); 00051 if ( !session ) { 00052 OE_WARN << LC << "No session - session is required for elevation clamping" << std::endl; 00053 return cx; 00054 } 00055 00056 // the map against which we'll be doing elevation clamping 00057 MapFrame mapf = session->createMapFrame( Map::ELEVATION_LAYERS ); 00058 00059 const SpatialReference* mapSRS = mapf.getProfile()->getSRS(); 00060 const SpatialReference* featureSRS = cx.profile()->getSRS(); 00061 00062 // establish an elevation query interface based on the features' SRS. 00063 ElevationQuery eq( mapf ); 00064 00065 NumericExpression scaleExpr; 00066 if ( _altitude.valid() && _altitude->verticalScale().isSet() ) 00067 scaleExpr = *_altitude->verticalScale(); 00068 00069 NumericExpression offsetExpr; 00070 if ( _altitude.valid() && _altitude->verticalOffset().isSet() ) 00071 offsetExpr = *_altitude->verticalOffset(); 00072 00073 bool clamp = 00074 _altitude->clamping() != AltitudeSymbol::CLAMP_NONE; 00075 00076 // whether to record a "minimum terrain" value 00077 bool collectHATs = 00078 _altitude->clamping() == AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN || 00079 _altitude->clamping() == AltitudeSymbol::CLAMP_ABSOLUTE; 00080 00081 for( FeatureList::iterator i = features.begin(); i != features.end(); ++i ) 00082 { 00083 Feature* feature = i->get(); 00084 double maxGeomZ = -DBL_MAX; 00085 double minGeomZ = DBL_MAX; 00086 double maxTerrainZ = -DBL_MAX; 00087 double minTerrainZ = DBL_MAX; 00088 double minHAT = DBL_MAX; 00089 double maxHAT = -DBL_MAX; 00090 00091 double scaleZ = 1.0; 00092 if ( _altitude.valid() && _altitude->verticalScale().isSet() ) 00093 scaleZ = feature->eval( scaleExpr ); 00094 00095 double offsetZ = 0.0; 00096 if ( _altitude.valid() && _altitude->verticalOffset().isSet() ) 00097 offsetZ = feature->eval( offsetExpr ); 00098 00099 GeometryIterator gi( feature->getGeometry() ); 00100 while( gi.hasMore() ) 00101 { 00102 Geometry* geom = gi.next(); 00103 00104 // clamps the entire array to the terrain using the specified resolution. 00105 if ( clamp ) 00106 { 00107 if ( collectHATs ) 00108 { 00109 std::vector<double> elevations; 00110 elevations.reserve( geom->size() ); 00111 eq.getElevations( geom->asVector(), featureSRS, elevations, _maxRes ); 00112 for( unsigned i=0; i<geom->size(); ++i ) 00113 { 00114 double z = (*geom)[i].z() * scaleZ + offsetZ; 00115 double hat = 00116 _altitude->clamping() == AltitudeSymbol::CLAMP_ABSOLUTE ? z - elevations[i] : 00117 z; 00118 00119 if ( hat > maxHAT ) 00120 maxHAT = hat; 00121 if ( hat < minHAT ) 00122 minHAT = hat; 00123 00124 double elev = elevations[i]; 00125 if ( elev > maxTerrainZ ) 00126 maxTerrainZ = elev; 00127 if ( elev < minTerrainZ ) 00128 minTerrainZ = elev; 00129 00130 (*geom)[i].z() = 00131 _altitude->clamping() == AltitudeSymbol::CLAMP_ABSOLUTE ? z : 00132 z + elevations[i]; 00133 } 00134 } 00135 else 00136 { 00137 eq.getElevations( geom->asVector(), featureSRS, true, _maxRes ); 00138 } 00139 } 00140 00141 for( Geometry::iterator i = geom->begin(); i != geom->end(); ++i ) 00142 { 00143 if ( !collectHATs ) 00144 { 00145 i->z() *= scaleZ; 00146 i->z() += offsetZ; 00147 } 00148 00149 if ( i->z() > maxGeomZ ) 00150 maxGeomZ = i->z(); 00151 if ( i->z() < minGeomZ ) 00152 minGeomZ = i->z(); 00153 } 00154 } 00155 00156 if ( minHAT != DBL_MAX ) 00157 { 00158 feature->set( "__min_hat", minHAT ); 00159 feature->set( "__max_hat", maxHAT ); 00160 } 00161 00162 if ( minGeomZ != DBL_MAX ) 00163 { 00164 feature->set( "__min_geom_z", minGeomZ ); 00165 feature->set( "__max_geom_z", maxGeomZ ); 00166 } 00167 00168 if ( minTerrainZ != DBL_MAX ) 00169 { 00170 feature->set( "__min_terrain_z", minTerrainZ ); 00171 feature->set( "__max_terrain_z", maxTerrainZ ); 00172 } 00173 } 00174 00175 return cx; 00176 }