osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthFeatures/ResampleFilter.cpp

Go to the documentation of this file.
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/ResampleFilter>
00020 #include <osgEarth/GeoMath>
00021 #include <osg/io_utils>
00022 #include <list>
00023 #include <deque>
00024 #include <cstdlib>
00025 
00026 using namespace osgEarth;
00027 using namespace osgEarth::Features;
00028 using namespace osgEarth::Symbology;
00029 
00030 bool
00031 ResampleFilter::isSupported()
00032 {
00033     return true;
00034 }
00035 
00036 ResampleFilter::ResampleFilter() :
00037 _minLen( 0 ),
00038 _maxLen( DBL_MAX ),
00039 _perturbThresh( 0 ),
00040 _resampleMode(RESAMPLE_LINEAR)
00041 {
00042     //NOP
00043 }
00044 
00045 ResampleFilter::ResampleFilter( double minLen, double maxLen ) :
00046 _minLen( minLen ),
00047 _maxLen( maxLen ),
00048 _perturbThresh( 0 ),
00049 _resampleMode(RESAMPLE_LINEAR)
00050 {
00051     // NOP
00052 }
00053 
00054 bool
00055 ResampleFilter::push( Feature* input, FilterContext& context )
00056 {
00057     if ( !input || !input->getGeometry() )
00058         return true;
00059 
00060     bool success = true;
00061 
00062     GeometryIterator i( input->getGeometry() );
00063     while( i.hasMore() )
00064     {        
00065         Geometry* part = i.next();
00066 
00067         if ( part->size() < 2 ) continue;
00068 
00069         unsigned int origSize = part->size();
00070 
00071         // copy the original part to a linked list. use a std::list since insert/erase
00072         // will not invalidate iterators.
00073         std::list<osg::Vec3d> plist;
00074         plist.insert( plist.begin(), part->begin(), part->end() );
00075 
00076         std::list<osg::Vec3d>::iterator v1 = plist.begin(); ++v1;
00077         std::list<osg::Vec3d>::iterator v0 = plist.begin();
00078         std::list<osg::Vec3d>::iterator last = plist.end(); --last;
00079 
00080         while( v0 != last )
00081         {
00082             bool increment = true;
00083 
00084             osg::Vec3d& p0 = *v0;
00085             osg::Vec3d& p1 = *v1;
00086             bool lastSeg = v1 == last;
00087             osg::Vec3d seg = p1 - p0;
00088 
00089             //OE_NOTICE << "p0=" << p0 << " to " << "p1=" << p1 << std::endl;
00090 
00091             osg::Vec3d p0Rad, p1Rad;
00092 
00093             if (_resampleMode.value() == RESAMPLE_GREATCIRCLE || _resampleMode.value() == RESAMPLE_RHUMB)
00094             {
00095                 p0Rad = osg::Vec3d(osg::DegreesToRadians(p0.x()), osg::DegreesToRadians(p0.y()), p0.z());
00096                 p1Rad = osg::Vec3d(osg::DegreesToRadians(p1.x()), osg::DegreesToRadians(p1.y()), p1.z());
00097             }
00098                        
00099             //Compute the length of the segment
00100             double segLen = 0.0;
00101             switch (_resampleMode.value())
00102             {
00103             case RESAMPLE_LINEAR:
00104                 segLen = seg.length();
00105                 break;
00106             case RESAMPLE_GREATCIRCLE:
00107                 segLen = GeoMath::distance(p0Rad.y(), p0Rad.x(), p1Rad.y(), p1Rad.x());
00108                 break;
00109             case RESAMPLE_RHUMB:
00110                 segLen = GeoMath::rhumbDistance(p0Rad.y(), p0Rad.x(), p1Rad.y(), p1Rad.x());
00111                 break;
00112             }
00113 
00114             if ( segLen < _minLen.value() && !lastSeg && plist.size() > 2 )
00115             {
00116                 v1 = plist.erase( v1 );
00117                 increment = false;
00118             }
00119             else if ( segLen > _maxLen.value() )
00120             {
00121                 //Compute the number of divisions to make
00122                 int numDivs = (1 + (int)(segLen/_maxLen.value()));
00123                 double newSegLen = segLen/(double)numDivs;
00124                 seg.normalize();
00125                 osg::Vec3d newPt;
00126                 double newHeight;
00127                 switch (_resampleMode.value())
00128                 {
00129                 case RESAMPLE_LINEAR:
00130                     {
00131                         newPt = p0 + seg * newSegLen;
00132                     }
00133                     break;
00134                 case RESAMPLE_GREATCIRCLE:
00135                     {
00136                         double bearing = GeoMath::bearing(p0Rad.y(), p0Rad.x(), p1Rad.y(), p1Rad.x());
00137                         double lat,lon;
00138                         GeoMath::destination(p0Rad.y(), p0Rad.x(), bearing, newSegLen, lat, lon);
00139                         newHeight = p0Rad.z() + ( p1Rad.z() - p0Rad.z() ) / (double)numDivs;
00140                         newPt = osg::Vec3d(osg::RadiansToDegrees(lon), osg::RadiansToDegrees(lat), newHeight);
00141                     }
00142                     break;
00143                 case RESAMPLE_RHUMB:
00144                     {
00145                         double bearing = GeoMath::rhumbBearing(p0Rad.y(), p0Rad.x(), p1Rad.y(), p1Rad.x());
00146                         double lat,lon;
00147                         GeoMath::rhumbDestination(p0Rad.y(), p0Rad.x(), bearing, newSegLen, lat, lon);
00148                         newHeight = p0Rad.z() + ( p1Rad.z() - p0Rad.z() ) / (double)numDivs;
00149                         newPt = osg::Vec3d(osg::RadiansToDegrees(lon), osg::RadiansToDegrees(lat), newHeight);
00150                     }
00151                     break;
00152                 }
00153                 
00154                 if ( _perturbThresh.value() > 0.0 && _perturbThresh.value() < newSegLen )
00155                 {
00156                     float r = 0.5 - (float)::rand()/(float)RAND_MAX;
00157                     newPt.x() += r;
00158                     newPt.y() += r;
00159                 }
00160                 v1 = plist.insert( v1, newPt );
00161             }
00162 
00163             if ( increment ) { ++v0; ++v1; }
00164         }
00165 
00166         part->clear();
00167         part->reserve( plist.size() );
00168         part->insert( part->begin(), plist.begin(), plist.end() );
00169 
00170         /*
00171         if ( origSize != part->size() )
00172         {
00173             OE_NOTICE << "Resampled part from " << origSize << " to " << part->size() << " points" << std::endl;
00174         }
00175         */
00176     }
00177     return success;
00178 }
00179 
00180 
00181 FilterContext
00182 ResampleFilter::push( FeatureList& input, FilterContext& context )
00183 {
00184     if ( !isSupported() )
00185     {
00186         OE_WARN << "ResampleFilter support not enabled" << std::endl;
00187         return context;
00188     }
00189 
00190     bool ok = true;
00191     for( FeatureList::iterator i = input.begin(); i != input.end(); ++i )
00192         if ( !push( i->get(), context ) )
00193             ok = false;
00194 
00195     return context;
00196 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines