osgEarth 2.1.1
|
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 }