osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthFeatures/TransformFilter.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/TransformFilter>
00020 #include <osg/ClusterCullingCallback>
00021 
00022 #define LC "[TransformFilter] "
00023 
00024 using namespace osgEarth;
00025 using namespace osgEarth::Features;
00026 using namespace osgEarth::Symbology;
00027 
00028 //---------------------------------------------------------------------------
00029 
00030 namespace 
00031 {
00032     osg::Matrixd
00033     createGeocentricInvRefFrame( const osg::Vec3d& input, const SpatialReference* inputSRS )
00034     {
00035         // convert to gencentric first:
00036         double X = input.x(), Y = input.y(), Z = input.z();
00037 
00038         osg::Matrixd localToWorld;
00039         localToWorld.makeTranslate(X,Y,Z);
00040 
00041         // normalize X,Y,Z
00042         double inverse_length = 1.0/sqrt(X*X + Y*Y + Z*Z);
00043         
00044         X *= inverse_length;
00045         Y *= inverse_length;
00046         Z *= inverse_length;
00047 
00048         double length_XY = sqrt(X*X + Y*Y);
00049         double inverse_length_XY = 1.0/length_XY;
00050 
00051         // Vx = |(-Y,X,0)|
00052         localToWorld(0,0) = -Y*inverse_length_XY;
00053         localToWorld(0,1) = X*inverse_length_XY;
00054         localToWorld(0,2) = 0.0;
00055 
00056         // Vy = /(-Z*X/(sqrt(X*X+Y*Y), -Z*Y/(sqrt(X*X+Y*Y),sqrt(X*X+Y*Y))| 
00057         double Vy_x = -Z*X*inverse_length_XY;
00058         double Vy_y = -Z*Y*inverse_length_XY;
00059         double Vy_z = length_XY;
00060         inverse_length = 1.0/sqrt(Vy_x*Vy_x + Vy_y*Vy_y + Vy_z*Vy_z);            
00061         localToWorld(1,0) = Vy_x*inverse_length;
00062         localToWorld(1,1) = Vy_y*inverse_length;
00063         localToWorld(1,2) = Vy_z*inverse_length;
00064 
00065         // Vz = (X,Y,Z)
00066         localToWorld(2,0) = X;
00067         localToWorld(2,1) = Y;
00068         localToWorld(2,2) = Z;
00069 
00070         return localToWorld;
00071     }
00072 
00073     void
00074     localizeGeometry( Feature* input, const osg::Matrixd& refFrame )
00075     {
00076         if ( input && input->getGeometry() )
00077         {
00078             GeometryIterator iter( input->getGeometry() );
00079             while( iter.hasMore() )
00080             {
00081                 Geometry* geom = iter.next();
00082                 for( unsigned int i=0; i<geom->size(); i++ )
00083                 {
00084                     (*geom)[i] = (*geom)[i] * refFrame;
00085                 }
00086             }
00087         }
00088     }
00089 }
00090 
00091 //---------------------------------------------------------------------------
00092 
00093 TransformFilter::TransformFilter() :
00094 _makeGeocentric( false ),
00095 _localize( false )
00096 {
00097     // nop
00098 }
00099 
00100 TransformFilter::TransformFilter( const osg::Matrixd& xform ) :
00101 _makeGeocentric( false ),
00102 _localize      ( false ),
00103 _mat           ( xform )
00104 {
00105     //nop
00106 }
00107 
00108 TransformFilter::TransformFilter(const SpatialReference* outputSRS,
00109                                  bool outputGeocentric ) :
00110 _outputSRS( outputSRS ),
00111 _makeGeocentric( outputGeocentric ),
00112 _localize( false )
00113 {
00114     //NOP
00115 }
00116 
00117 bool
00118 TransformFilter::push( Feature* input, FilterContext& context )
00119 {
00120     if ( !input || !input->getGeometry() )
00121         return true;
00122 
00123     bool needsSRSXform =
00124         _outputSRS.valid() &&
00125         ( ! context.profile()->getSRS()->isEquivalentTo( _outputSRS.get() ) );
00126 
00127     bool needsMatrixXform = !_mat.isIdentity();
00128 
00129     // optimize: do nothing if nothing needs doing
00130     if ( !needsSRSXform && !_makeGeocentric && !_localize && !needsMatrixXform )
00131         return true;
00132 
00133     // iterate over the feature geometry.
00134     GeometryIterator iter( input->getGeometry() );
00135     while( iter.hasMore() )
00136     {
00137         Geometry* geom = iter.next();
00138 
00139         // pre-transform the point before doing an SRS transformation.
00140         if ( needsMatrixXform )
00141         {
00142             for( unsigned i=0; i < geom->size(); ++i )
00143                 (*geom)[i] = (*geom)[i] * _mat;
00144         }
00145 
00146         // first transform the geometry to the output SRS:            
00147         if ( needsSRSXform )
00148             context.profile()->getSRS()->transformPoints( _outputSRS.get(), geom->asVector(), false );
00149 
00150         // convert to ECEF if required:
00151         if ( _makeGeocentric )
00152             _outputSRS->transformToECEF( geom->asVector(), false );
00153 
00154         // update the bounding box.
00155         if ( _localize )
00156         {
00157             for( unsigned i=0; i<geom->size(); ++i )
00158                 _bbox.expandBy( (*geom)[i] );
00159         }
00160     }
00161 
00162     return true;
00163 }
00164 
00165 FilterContext
00166 TransformFilter::push( FeatureList& input, FilterContext& incx )
00167 {
00168     _bbox = osg::BoundingBoxd();
00169 
00170     // first transform all the points into the output SRS, collecting a bounding box as we go:
00171     bool ok = true;
00172     for( FeatureList::iterator i = input.begin(); i != input.end(); i++ )
00173         if ( !push( i->get(), incx ) )
00174             ok = false;
00175 
00176     FilterContext outcx( incx );
00177     outcx.isGeocentric() = _makeGeocentric;
00178 
00179     if ( _outputSRS.valid() )
00180     {
00181         if ( incx.extent()->isValid() )
00182             outcx.profile() = new FeatureProfile( incx.extent()->transform( _outputSRS.get() ) );
00183         else
00184             outcx.profile() = new FeatureProfile( incx.profile()->getExtent().transform( _outputSRS.get() ) );
00185     }
00186 
00187     // set the reference frame to shift data to the centroid. This will
00188     // prevent floating point precision errors in the openGL pipeline for
00189     // properly gridded data.
00190     if ( _bbox.valid() && _localize )
00191     {
00192         // create a suitable reference frame:
00193         osg::Matrixd localizer;
00194         if ( _makeGeocentric )
00195         {
00196             localizer = createGeocentricInvRefFrame( _bbox.center(), _outputSRS.get() );
00197             localizer.invert( localizer );
00198         }
00199         else
00200         {
00201             localizer = osg::Matrixd::translate( -_bbox.center() );
00202         }
00203 
00204         // localize the geometry relative to the reference frame.
00205         for( FeatureList::iterator i = input.begin(); i != input.end(); i++ )
00206         {
00207             localizeGeometry( i->get(), localizer );
00208         }
00209         outcx.setReferenceFrame( localizer );
00210     }
00211 
00212     return outcx;
00213 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines