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/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 }