osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthUtil/ImageOverlay.cpp

Go to the documentation of this file.
00001 #include <osgEarthUtil/ImageOverlay>
00002 
00003 #include <osg/Geode>
00004 #include <osg/ShapeDrawable>
00005 #include <osg/Texture2D>
00006 #include <osgEarthSymbology/MeshSubdivider>
00007 #include <osgEarth/FindNode>
00008 #include <osg/io_utils>
00009 #include <algorithm>
00010 
00011 using namespace osgEarth;
00012 using namespace osgEarth::Util;
00013 using namespace osgEarth::Symbology;
00014 
00015 /***************************************************************************/
00016 
00017 void clampLatitude(osg::Vec2d& l)
00018 {
00019     l.y() = osg::clampBetween( l.y(), -90.0, 90.0);
00020 }
00021 
00022 ImageOverlay::ImageOverlay(MapNode* mapNode, osg::Image* image):
00023 DrapeableNode(mapNode, true),
00024 _lowerLeft(10,10),
00025 _lowerRight(20, 10),
00026 _upperRight(20,20),
00027 _upperLeft(10, 20),
00028 _image(image),
00029 _dirty(false),
00030 _alpha(1.0f)
00031 {        
00032     postCTOR();
00033 }
00034 
00035 void
00036 ImageOverlay::postCTOR()
00037 {
00038     _geode = new osg::Geode;
00039     //addChild( _geode );    
00040 
00041     setNode( _geode );
00042 
00043     init();    
00044     ADJUST_UPDATE_TRAV_COUNT( this, 1 );    
00045 }
00046 
00047 void
00048 ImageOverlay::init()
00049 {
00050     OpenThreads::ScopedLock< OpenThreads::Mutex > lock(_mutex);    
00051 
00052     double height = 0;
00053     osg::Geometry* geometry = new osg::Geometry();
00054     osg::Vec3d ll;
00055     const osg::EllipsoidModel* ellipsoid = _mapNode->getMap()->getProfile()->getSRS()->getEllipsoid();
00056     ellipsoid->convertLatLongHeightToXYZ(osg::DegreesToRadians(_lowerLeft.y()), osg::DegreesToRadians(_lowerLeft.x()), height, ll.x(), ll.y(), ll.z());
00057 
00058     osg::Vec3d lr;
00059     ellipsoid->convertLatLongHeightToXYZ(osg::DegreesToRadians(_lowerRight.y()), osg::DegreesToRadians(_lowerRight.x()), height, lr.x(), lr.y(), lr.z());
00060 
00061     osg::Vec3d ur;
00062     ellipsoid->convertLatLongHeightToXYZ(osg::DegreesToRadians(_upperRight.y()), osg::DegreesToRadians(_upperRight.x()), height, ur.x(), ur.y(), ur.z());
00063 
00064     osg::Vec3d ul;
00065     ellipsoid->convertLatLongHeightToXYZ(osg::DegreesToRadians(_upperLeft.y()), osg::DegreesToRadians(_upperLeft.x()), height, ul.x(), ul.y(), ul.z());
00066 
00067 
00068     osg::Vec3Array* verts = new osg::Vec3Array(4);
00069     (*verts)[0] = ll;
00070     (*verts)[1] = lr;
00071     (*verts)[2] = ur;
00072     (*verts)[3] = ul;
00073     
00074     geometry->setVertexArray( verts );
00075 
00076     osg::Vec4Array* colors = new osg::Vec4Array(1);
00077     (*colors)[0] = osg::Vec4(1,1,1,_alpha);
00078 
00079     geometry->setColorArray( colors );
00080     geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
00081 
00082      GLuint tris[6] = { 0, 1, 2,
00083                         0, 2, 3
00084                       };        
00085     geometry->addPrimitiveSet(new osg::DrawElementsUInt( GL_TRIANGLES, 6, tris ) );
00086 
00087     bool flip = false;
00088     if (_image.valid())
00089     {
00090         //Create the texture
00091         osg::Texture2D* texture = new osg::Texture2D(_image.get());
00092         texture->setResizeNonPowerOfTwoHint(false);
00093         _geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);    
00094         flip = _image->getOrigin()==osg::Image::TOP_LEFT;
00095     }
00096 
00097     osg::Vec2Array* texcoords = new osg::Vec2Array(4);
00098     (*texcoords)[0].set(0.0f,flip ? 1.0 : 0.0f);
00099     (*texcoords)[1].set(1.0f,flip ? 1.0 : 0.0f);
00100     (*texcoords)[2].set(1.0f,flip ? 0.0 : 1.0f);
00101     (*texcoords)[3].set(0.0f,flip ? 0.0 : 1.0f);
00102     geometry->setTexCoordArray(0, texcoords);
00103         
00104     MeshSubdivider ms;
00105     ms.run(*geometry, osg::DegreesToRadians(5.0), GEOINTERP_RHUMB_LINE);
00106 
00107     _geode->removeDrawables(0, _geode->getNumDrawables() );
00108 
00109     _geode->addDrawable( geometry );
00110 
00111     _geometry = geometry;
00112 
00113     _dirty = false;
00114 }
00115 
00116 osg::Image*
00117 ImageOverlay::getImage() const
00118 {
00119     return _image.get();
00120 }
00121 
00122 void ImageOverlay::setImage( osg::Image* image )
00123 {
00124     if (_image != image)
00125     {
00126         _image = image;
00127         dirty();        
00128     }
00129 }
00130 
00131 float
00132 ImageOverlay::getAlpha() const
00133 {
00134     return _alpha;
00135 }
00136 
00137 void
00138 ImageOverlay::setAlpha(float alpha)
00139 {
00140     if (_alpha != alpha)
00141     {
00142         _alpha = osg::clampBetween(alpha, 0.0f, 1.0f);
00143         dirty();
00144     }
00145 }
00146 
00147 void
00148 ImageOverlay::clampLatitudes()
00149 {
00150     clampLatitude( _lowerLeft );
00151     clampLatitude( _lowerRight );
00152     clampLatitude( _upperLeft );
00153     clampLatitude( _upperRight );
00154 }
00155 
00156 
00157 osg::Vec2d
00158 ImageOverlay::getCenter() const
00159 {
00160     return (_lowerLeft + _lowerRight + _upperRight + _upperLeft) / 4.0;
00161 }
00162 
00163 void
00164 ImageOverlay::setCenter(double lon_deg, double lat_deg)
00165 {
00166     osg::Vec2d center = getCenter();
00167     osg::Vec2d newCenter(lon_deg, lat_deg);
00168     osg::Vec2d offset =  newCenter - center;
00169     setCorners(_lowerLeft += offset, _lowerRight += offset,
00170                _upperLeft += offset, _upperRight += offset);    
00171 }
00172 
00173 void
00174 ImageOverlay::setNorth(double value_deg)
00175 {
00176     _upperRight.y() = value_deg;
00177     _upperLeft.y()  = value_deg;
00178     clampLatitudes();
00179     dirty();
00180 }
00181 
00182 void
00183 ImageOverlay::setSouth(double value_deg)
00184 {
00185     _lowerRight.y() = value_deg;
00186     _lowerLeft.y() = value_deg;
00187     clampLatitudes();
00188     dirty();
00189 }
00190 
00191 void
00192 ImageOverlay::setEast(double value_deg)
00193 {
00194     _upperRight.x() = value_deg;
00195     _lowerRight.x() = value_deg;
00196     dirty();
00197 }
00198 
00199 void
00200 ImageOverlay::setWest(double value_deg)
00201 {
00202     _lowerLeft.x() = value_deg;
00203     _upperLeft.x() = value_deg;
00204     dirty();
00205 }
00206 
00207 void
00208 ImageOverlay::setCorners(const osg::Vec2d& lowerLeft, const osg::Vec2d& lowerRight, 
00209         const osg::Vec2d& upperLeft, const osg::Vec2d& upperRight)
00210 {
00211     _lowerLeft = lowerLeft;
00212     _lowerRight = lowerRight;
00213     _upperLeft = upperLeft;
00214     _upperRight = upperRight;
00215     clampLatitudes();
00216     
00217     dirty();
00218 }
00219 
00220 osgEarth::Bounds
00221 ImageOverlay::getBounds() const
00222 {
00223     osgEarth::Bounds bounds;
00224     bounds.expandBy(_lowerLeft.x(), _lowerLeft.y());
00225     bounds.expandBy(_lowerRight.x(), _lowerRight.y());
00226     bounds.expandBy(_upperLeft.x(), _upperLeft.y());
00227     bounds.expandBy(_upperRight.x(), _upperRight.y());
00228     return bounds;
00229 }
00230 
00231 void ImageOverlay::setBounds(const osgEarth::Bounds &extent)
00232 {
00233     setCorners(osg::Vec2d(extent.xMin(), extent.yMin()), osg::Vec2d(extent.xMax(), extent.yMin()),
00234                osg::Vec2d(extent.xMin(), extent.yMax()), osg::Vec2d(extent.xMax(), extent.yMax()));
00235 }
00236 
00237 void
00238 ImageOverlay::setBoundsAndRotation(const osgEarth::Bounds& b, const Angular& rot)
00239 {
00240     double rot_rad = rot.as(Units::RADIANS);
00241 
00242     if ( osg::equivalent( rot_rad, 0.0 ) )
00243     {
00244         setBounds( b );
00245     }
00246     else
00247     {
00248         osg::Vec2d ll( b.xMin(), b.yMin() );
00249         osg::Vec2d ul( b.xMin(), b.yMax() );
00250         osg::Vec2d ur( b.xMax(), b.yMax() );
00251         osg::Vec2d lr( b.xMax(), b.yMin() );
00252 
00253         double sinR = sin(-rot_rad), cosR = cos(-rot_rad);
00254 
00255         osg::Vec2d c( 0.5*(b.xMax()+b.xMin()), 0.5*(b.yMax()+b.yMin()) );
00256 
00257         // there must be a better way, but my internet is down so i can't look it up with now..
00258 
00259         osg::ref_ptr<SpatialReference> srs = SpatialReference::create("wgs84");
00260         osg::ref_ptr<SpatialReference> utm = srs->createUTMFromLongitude( c.x() );
00261 
00262         osg::Vec2d ll_utm, ul_utm, ur_utm, lr_utm, c_utm;
00263         srs->transform2D( ll.x(), ll.y(), utm.get(), ll_utm.x(), ll_utm.y() );
00264         srs->transform2D( ul.x(), ul.y(), utm.get(), ul_utm.x(), ul_utm.y() );
00265         srs->transform2D( ur.x(), ur.y(), utm.get(), ur_utm.x(), ur_utm.y() );
00266         srs->transform2D( lr.x(), lr.y(), utm.get(), lr_utm.x(), lr_utm.y() );
00267         srs->transform2D( c.x(),  c.y(),  utm.get(), c_utm.x(),  c_utm.y()  );
00268 
00269         osg::Vec2d llp( cosR*(ll_utm.x()-c_utm.x()) - sinR*(ll_utm.y()-c_utm.y()), sinR*(ll_utm.x()-c_utm.x()) + cosR*(ll_utm.y()-c_utm.y()) );
00270         osg::Vec2d ulp( cosR*(ul_utm.x()-c_utm.x()) - sinR*(ul_utm.y()-c_utm.y()), sinR*(ul_utm.x()-c_utm.x()) + cosR*(ul_utm.y()-c_utm.y()) );
00271         osg::Vec2d urp( cosR*(ur_utm.x()-c_utm.x()) - sinR*(ur_utm.y()-c_utm.y()), sinR*(ur_utm.x()-c_utm.x()) + cosR*(ur_utm.y()-c_utm.y()) );
00272         osg::Vec2d lrp( cosR*(lr_utm.x()-c_utm.x()) - sinR*(lr_utm.y()-c_utm.y()), sinR*(lr_utm.x()-c_utm.x()) + cosR*(lr_utm.y()-c_utm.y()) );    
00273 
00274         utm->transform2D( (llp+c_utm).x(), (llp+c_utm).y(), srs.get(), ll.x(), ll.y() );
00275         utm->transform2D( (ulp+c_utm).x(), (ulp+c_utm).y(), srs.get(), ul.x(), ul.y() );
00276         utm->transform2D( (urp+c_utm).x(), (urp+c_utm).y(), srs.get(), ur.x(), ur.y() );
00277         utm->transform2D( (lrp+c_utm).x(), (lrp+c_utm).y(), srs.get(), lr.x(), lr.y() );
00278 
00279         setCorners( ll, lr, ul, ur );
00280     }
00281 }
00282 
00283 void
00284 ImageOverlay::setLowerLeft(double lon_deg, double lat_deg)
00285 {
00286     _lowerLeft = osg::Vec2d(lon_deg, lat_deg);
00287     clampLatitudes();
00288     dirty();    
00289 }
00290 
00291 void
00292 ImageOverlay::setLowerRight(double lon_deg, double lat_deg)
00293 {
00294     _lowerRight = osg::Vec2d(lon_deg, lat_deg);
00295     clampLatitudes();
00296     dirty();    
00297 }
00298 
00299 void
00300 ImageOverlay::setUpperRight(double lon_deg, double lat_deg)
00301 {
00302     _upperRight = osg::Vec2d(lon_deg, lat_deg);
00303     clampLatitudes();
00304     dirty();
00305 }
00306 
00307 void
00308 ImageOverlay::setUpperLeft(double lon_deg, double lat_deg)
00309 {
00310     _upperLeft = osg::Vec2d(lon_deg, lat_deg);
00311     clampLatitudes();
00312     dirty();
00313 }
00314 
00315 osg::Vec2d
00316 ImageOverlay::getControlPoint(ControlPoint controlPoint)
00317 {
00318     switch (controlPoint)
00319     {
00320     case CONTROLPOINT_CENTER:
00321         return getCenter();
00322     case CONTROLPOINT_UPPER_LEFT:
00323         return getUpperLeft();
00324     case CONTROLPOINT_LOWER_LEFT:
00325         return getLowerLeft();
00326     case CONTROLPOINT_UPPER_RIGHT:
00327         return getUpperRight();
00328     case CONTROLPOINT_LOWER_RIGHT:
00329         return getLowerRight();
00330     default:
00331         return getCenter();
00332     }       
00333 }
00334 
00335 void
00336 ImageOverlay::setControlPoint(ControlPoint controlPoint, double lon_deg, double lat_deg,  bool singleVert)
00337 {
00338     switch (controlPoint)
00339     {
00340     case CONTROLPOINT_CENTER:
00341         return setCenter(lon_deg, lat_deg);
00342         break;
00343     case CONTROLPOINT_UPPER_LEFT:
00344         if (singleVert)
00345         {
00346             setUpperLeft(lon_deg, lat_deg);
00347         }
00348         else
00349         {
00350             setNorth(lat_deg);
00351             setWest(lon_deg);
00352         }
00353         break;
00354     case CONTROLPOINT_LOWER_LEFT:
00355         if (singleVert)
00356         {
00357             setLowerLeft(lon_deg, lat_deg);
00358         }
00359         else
00360         {
00361             setSouth(lat_deg);
00362             setWest(lon_deg);
00363         }
00364         break;
00365     case CONTROLPOINT_UPPER_RIGHT:
00366         if (singleVert)
00367         {
00368             setUpperRight(lon_deg, lat_deg);
00369         }
00370         else
00371         {
00372             setNorth( lat_deg);
00373             setEast( lon_deg );            
00374         }
00375         break;
00376     case CONTROLPOINT_LOWER_RIGHT:
00377         if (singleVert)
00378         {
00379             setLowerRight(lon_deg, lat_deg);
00380         }
00381         else
00382         {
00383             setSouth( lat_deg );
00384             setEast( lon_deg );
00385         }
00386         break;
00387     }
00388 }
00389 
00390 void
00391 ImageOverlay::traverse(osg::NodeVisitor &nv)
00392 {     
00393     if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && _dirty)
00394     {
00395         init();        
00396     }
00397     DrapeableNode::traverse(nv);
00398 }
00399 
00400 void ImageOverlay::dirty()
00401 {
00402     {
00403         OpenThreads::ScopedLock< OpenThreads::Mutex > lock(_mutex);
00404         _dirty = true;
00405     }
00406 
00407     for( CallbackList::iterator i = _callbacks.begin(); i != _callbacks.end(); i++ )
00408     {
00409         i->get()->onOverlayChanged();
00410     }
00411 }
00412 
00413 void 
00414 ImageOverlay::addCallback( ImageOverlayCallback* cb )
00415 {
00416     if ( cb )
00417         this->_callbacks.push_back( cb );
00418 }
00419 
00420 void 
00421 ImageOverlay::removeCallback( ImageOverlayCallback* cb )
00422 {
00423     CallbackList::iterator i = std::find( _callbacks.begin(), _callbacks.end(), cb);
00424     if (i != _callbacks.end())
00425     {
00426         _callbacks.erase( i );
00427     }    
00428 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines