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 "CubeManifold" 00020 #include <osgEarth/Cube> 00021 00022 #define NEG_Y 0 00023 #define POS_Y 1 00024 #define NEG_X 2 00025 #define POS_X 3 00026 #define NEG_Z 4 00027 #define POS_Z 5 00028 00029 #define LC "[CubeManifold] " 00030 00031 CubeManifold::CubeManifold() 00032 { 00033 _profile = new osgEarth::UnifiedCubeProfile(); 00034 _ellipsoid = _profile->getSRS()->getGeographicSRS()->getEllipsoid(); 00035 } 00036 00037 void 00038 CubeManifold::initialize( MeshManager* mesh ) 00039 { 00040 // diamonds at or below level 3 are static and cannot be removed. 00041 // Level 1 is the first Quadtree Ancestor. Level 3 contains the first Quadtree 00042 // decendants (the decendants of the Level 1 quadtrees). 00043 mesh->_minGeomLevel = 1; 00044 mesh->_minActiveLevel = 3; 00045 00046 // Construct the eight root "vertex diamonds". These are used only for their 00047 // vertex positions (as grandparents of the root edge diamonds). They have 00048 // no children or ancestors of their own. 00049 _vd[0] = new Diamond(mesh, TileKey(), 0, "vd0"); // X, -Y, Z 00050 _vd[0]->setCoord( p(1, -1, 1) ); 00051 _vd[0]->_childValence = 3; 00052 00053 _vd[1] = new Diamond(mesh, TileKey(), 0, "vd1"); // -X, Y, Z 00054 _vd[1]->setCoord( p(-1, 1, 1) ); 00055 _vd[0]->_childValence = 3; 00056 00057 _vd[2] = new Diamond(mesh, TileKey(), 0, "vd2"); // -X, -Y, -Z 00058 _vd[2]->setCoord( p(-1, -1, -1) ); 00059 _vd[0]->_childValence = 3; 00060 00061 _vd[3] = new Diamond(mesh, TileKey(), 0, "vd3"); // X, Y, -Z 00062 _vd[3]->setCoord( p(1, 1, -1) ); 00063 _vd[0]->_childValence = 3; 00064 00065 _vd[4] = new Diamond(mesh, TileKey(), 0, "vd4"); // X, Y, Z 00066 _vd[4]->setCoord( p(1, 1, 1) ); 00067 _vd[0]->_childValence = 3; 00068 00069 _vd[5] = new Diamond(mesh, TileKey(), 0, "vd5"); // -X, -Y, Z 00070 _vd[5]->setCoord( p(-1, -1, 1) ); 00071 _vd[0]->_childValence = 3; 00072 00073 _vd[6] = new Diamond(mesh, TileKey(), 0, "vd6"); // X, -Y, -Z 00074 _vd[6]->setCoord( p(1, -1, -1) ); 00075 _vd[0]->_childValence = 3; 00076 00077 _vd[7] = new Diamond(mesh, TileKey(), 0, "vd7"); // -X, Y, -Z 00078 _vd[7]->setCoord( p(-1, 1, -1) ); 00079 _vd[0]->_childValence = 3; 00080 00081 // Construct the 6 face diamonds. Exactly 2 faces parent each edge diamond (constructed 00082 // later). The vertex position of each face diamond resides as the center of that face 00083 // on the cube. The faces are carefully oriented so that child diamonds are anchored 00084 // (i.e. have their QUADTREE ancestor) at the PARENT_L and PARENT_R positions. This is 00085 // critical for proper subdivision and orientation propagation. 00086 00087 // The first 3 share vd0 as a common PARENT_L ancestor: 00088 00089 _fd[NEG_Y] = new Diamond(mesh, TileKey(0,1,0,_profile.get()), 1, "fd -y"); // -Y face (-90=>0 long) 00090 _fd[NEG_Y]->setCoord( p(0, -1, 0) ); 00091 _fd[NEG_Y]->_a[PARENT_R] = _vd[2]; 00092 _fd[NEG_Y]->_a[PARENT_L] = _vd[0]; 00093 _fd[NEG_Y]->_a[QUADTREE] = _vd[5]; 00094 _fd[NEG_Y]->_a[GDPARENT] = _vd[6]; 00095 _fd[NEG_Y]->_orientation = 6; 00096 00097 _fd[POS_X] = new Diamond(mesh, TileKey(0,2,0,_profile.get()), 1, "fd +x"); // +X face (0=>90 long) 00098 _fd[POS_X]->setCoord( p(1, 0, 0) ); 00099 _fd[POS_X]->_a[PARENT_R] = _vd[3]; 00100 _fd[POS_X]->_a[PARENT_L] = _vd[0]; 00101 _fd[POS_X]->_a[QUADTREE] = _vd[6]; 00102 _fd[POS_X]->_a[GDPARENT] = _vd[4]; 00103 _fd[POS_X]->_orientation = 0; 00104 00105 _fd[POS_Z] = new Diamond(mesh, TileKey(0,4,0,_profile.get()), 1, "fd +z"); // +Z face (north polar) 00106 _fd[POS_Z]->setCoord( p(0, 0, 1) ); 00107 _fd[POS_Z]->_a[PARENT_R] = _vd[1]; 00108 _fd[POS_Z]->_a[PARENT_L] = _vd[0]; 00109 _fd[POS_Z]->_a[QUADTREE] = _vd[4]; 00110 _fd[POS_Z]->_a[GDPARENT] = _vd[5]; 00111 _fd[POS_Z]->_orientation = 6; // 4 00112 00113 // The next 3 share vd7 as a common QUADTREE ancestor: 00114 00115 _fd[POS_Y] = new Diamond(mesh, TileKey(0,3,0,_profile.get()), 1, "fd +y"); // +Y face (90=>180 long) 00116 _fd[POS_Y]->setCoord( p(0, 1, 0) ); 00117 _fd[POS_Y]->_a[PARENT_R] = _vd[1]; 00118 _fd[POS_Y]->_a[PARENT_L] = _vd[3]; 00119 _fd[POS_Y]->_a[QUADTREE] = _vd[7]; 00120 _fd[POS_Y]->_a[GDPARENT] = _vd[4]; 00121 _fd[POS_Y]->_orientation = 2; 00122 00123 _fd[NEG_X] = new Diamond(mesh, TileKey(0,0,0,_profile.get()), 1, "fd -x"); // -X face (-180=>-90 long) 00124 _fd[NEG_X]->setCoord( p(-1, 0, 0) ); 00125 _fd[NEG_X]->_a[PARENT_R] = _vd[2]; 00126 _fd[NEG_X]->_a[PARENT_L] = _vd[1]; 00127 _fd[NEG_X]->_a[QUADTREE] = _vd[7]; 00128 _fd[NEG_X]->_a[GDPARENT] = _vd[5]; 00129 _fd[NEG_X]->_orientation = 0; 00130 00131 _fd[NEG_Z] = new Diamond(mesh, TileKey(0,5,0,_profile.get()), 1, "fd -z"); // -Z face (south polar) 00132 _fd[NEG_Z]->setCoord( p(0, 0, -1) ); 00133 _fd[NEG_Z]->_a[PARENT_R] = _vd[3]; 00134 _fd[NEG_Z]->_a[PARENT_L] = _vd[2]; 00135 _fd[NEG_Z]->_a[QUADTREE] = _vd[7]; 00136 _fd[NEG_Z]->_a[GDPARENT] = _vd[6]; 00137 _fd[NEG_Z]->_orientation = 0; 00138 00139 // Next, construct the 12 root edge diamonds. These are the roots of the global 00140 // bintree, and are the first elements that actually get drawn. Each edge diamond 00141 // represents an edge of the cube, with its vertex position at the midpoint of that 00142 // edge. Each edge diamond has two face diamonds as parents, and one vertex diamond 00143 // as its "quadtree" ancestor. That adds up to the 4 verts of the diamond. 00144 00145 // GROUP OF THREE under the vd[0] "quadtree": 00146 _ed[0] = new Diamond(mesh, TileKey(), 2, "ed0"); 00147 _ed[0]->setCoord( p(0, -1, 1) ); 00148 _ed[0]->_a[PARENT_R] = _fd[POS_Z]; 00149 _ed[0]->_a[PARENT_L] = _fd[NEG_Y]; 00150 _ed[0]->_a[QUADTREE] = _vd[0]; 00151 _ed[0]->_a[GDPARENT] = _vd[5]; 00152 // _ed[0]->_color = RED; 00153 00154 _ed[1] = new Diamond(mesh, TileKey(), 2, "ed1"); 00155 _ed[1]->setCoord( p(1, -1, 0 ) ); 00156 _ed[1]->_a[PARENT_R] = _fd[NEG_Y]; 00157 _ed[1]->_a[PARENT_L] = _fd[POS_X]; 00158 _ed[1]->_a[QUADTREE] = _vd[0]; 00159 _ed[1]->_a[GDPARENT] = _vd[6]; 00160 //_ed[1]->_color = RED; 00161 00162 _ed[2] = new Diamond(mesh, TileKey(), 2, "ed2"); 00163 _ed[2]->setCoord( p(1, 0, 1) ); 00164 _ed[2]->_a[PARENT_R] = _fd[POS_X]; 00165 _ed[2]->_a[PARENT_L] = _fd[POS_Z]; 00166 _ed[2]->_a[QUADTREE] = _vd[0]; 00167 _ed[2]->_a[GDPARENT] = _vd[4]; 00168 //_ed[2]->_color = RED; 00169 00170 // GROUP OF THREE under the vd[1] "quadtree": 00171 _ed[3] = new Diamond(mesh, TileKey(), 2, "ed3"); 00172 _ed[3]->setCoord( p(0, 1, 1) ); 00173 _ed[3]->_a[PARENT_R] = _fd[POS_Z]; 00174 _ed[3]->_a[PARENT_L] = _fd[POS_Y]; 00175 _ed[3]->_a[QUADTREE] = _vd[1]; 00176 _ed[3]->_a[GDPARENT] = _vd[4]; 00177 //_ed[3]->_color = GREEN; 00178 00179 _ed[4] = new Diamond(mesh, TileKey(), 2, "ed4"); 00180 _ed[4]->setCoord( p(-1, 1, 0) ); 00181 _ed[4]->_a[PARENT_R] = _fd[POS_Y]; 00182 _ed[4]->_a[PARENT_L] = _fd[NEG_X]; 00183 _ed[4]->_a[QUADTREE] = _vd[1]; 00184 _ed[4]->_a[GDPARENT] = _vd[7]; 00185 //_ed[4]->_color = GREEN; 00186 00187 _ed[5] = new Diamond(mesh, TileKey(), 2, "ed5"); 00188 _ed[5]->setCoord( p(-1, 0, 1) ); 00189 _ed[5]->_a[PARENT_R] = _fd[NEG_X]; 00190 _ed[5]->_a[PARENT_L] = _fd[POS_Z]; 00191 _ed[5]->_a[QUADTREE] = _vd[1]; 00192 _ed[5]->_a[GDPARENT] = _vd[5]; 00193 //_ed[5]->_color = GREEN; 00194 00195 // GROUP OF THREE under the vd[2] "quadtree": 00196 _ed[6] = new Diamond(mesh, TileKey(), 2, "ed6"); 00197 _ed[6]->setCoord( p(-1, -1, 0) ); 00198 _ed[6]->_a[PARENT_R] = _fd[NEG_Y]; 00199 _ed[6]->_a[PARENT_L] = _fd[NEG_X]; 00200 _ed[6]->_a[QUADTREE] = _vd[2]; 00201 _ed[6]->_a[GDPARENT] = _vd[5]; 00202 //_ed[6]->_color = BLUE; 00203 00204 _ed[7] = new Diamond(mesh, TileKey(), 2, "ed7"); 00205 _ed[7]->setCoord( p(-1, 0, -1) ); 00206 _ed[7]->_a[PARENT_R] = _fd[NEG_X]; 00207 _ed[7]->_a[PARENT_L] = _fd[NEG_Z]; 00208 _ed[7]->_a[QUADTREE] = _vd[2]; 00209 _ed[7]->_a[GDPARENT] = _vd[7]; 00210 //_ed[7]->_color = BLUE; 00211 00212 _ed[8] = new Diamond(mesh, TileKey(), 2, "ed8"); 00213 _ed[8]->setCoord( p(0, -1, -1) ); 00214 _ed[8]->_a[PARENT_R] = _fd[NEG_Z]; 00215 _ed[8]->_a[PARENT_L] = _fd[NEG_Y]; 00216 _ed[8]->_a[QUADTREE] = _vd[2]; 00217 _ed[8]->_a[GDPARENT] = _vd[6]; 00218 //_ed[8]->_color = BLUE; 00219 00220 // GROUP OF THREE under the vd[3] "quadtree": 00221 _ed[9] = new Diamond(mesh, TileKey(), 2, "ed9"); 00222 _ed[9]->setCoord( p(1, 1, 0) ); 00223 _ed[9]->_a[PARENT_R] = _fd[POS_Y]; 00224 _ed[9]->_a[PARENT_L] = _fd[POS_X]; 00225 _ed[9]->_a[QUADTREE] = _vd[3]; 00226 _ed[9]->_a[GDPARENT] = _vd[4]; 00227 //_ed[9]->_color = YELLOW; 00228 00229 _ed[10] = new Diamond(mesh, TileKey(), 2, "ed10"); 00230 _ed[10]->setCoord( p(1, 0, -1) ); 00231 _ed[10]->_a[PARENT_R] = _fd[POS_X]; 00232 _ed[10]->_a[PARENT_L] = _fd[NEG_Z]; 00233 _ed[10]->_a[QUADTREE] = _vd[3]; 00234 _ed[10]->_a[GDPARENT] = _vd[6]; 00235 //_ed[10]->_color = YELLOW; 00236 00237 _ed[11] = new Diamond(mesh, TileKey(), 2, "ed11"); 00238 _ed[11]->setCoord( p(0, 1, -1) ); 00239 _ed[11]->_a[PARENT_R] = _fd[NEG_Z]; 00240 _ed[11]->_a[PARENT_L] = _fd[POS_Y]; 00241 _ed[11]->_a[QUADTREE] = _vd[3]; 00242 _ed[11]->_a[GDPARENT] = _vd[7]; 00243 //_ed[11]->_color = YELLOW; 00244 00245 // NEXT, set the pointers from each face diamond to its 4 children. We can double- 00246 // check these by looking at the ancestor assignments above. They should match up. 00247 // At the same time, we assign the back pointers from each of the edge diamonds to 00248 // their 2 parents. 00249 00250 _fd[POS_X]->setChild( 0, _ed[10].get() ); 00251 _fd[POS_X]->setChild( 1, _ed[9].get() ); 00252 _fd[POS_X]->setChild( 2, _ed[2].get() ); 00253 _fd[POS_X]->setChild( 3, _ed[1].get() ); 00254 00255 _fd[NEG_Y]->setChild( 0, _ed[6].get() ); 00256 _fd[NEG_Y]->setChild( 1, _ed[8].get() ); 00257 _fd[NEG_Y]->setChild( 2, _ed[1].get() ); 00258 _fd[NEG_Y]->setChild( 3, _ed[0].get() ); 00259 00260 _fd[POS_Z]->setChild( 0, _ed[3].get() ); 00261 _fd[POS_Z]->setChild( 1, _ed[5].get() ); 00262 _fd[POS_Z]->setChild( 2, _ed[0].get() ); 00263 _fd[POS_Z]->setChild( 3, _ed[2].get() ); 00264 00265 _fd[POS_Y]->setChild( 0, _ed[4].get() ); 00266 _fd[POS_Y]->setChild( 1, _ed[3].get() ); 00267 _fd[POS_Y]->setChild( 2, _ed[9].get() ); 00268 _fd[POS_Y]->setChild( 3, _ed[11].get() ); 00269 00270 _fd[NEG_X]->setChild( 0, _ed[7].get() ); 00271 _fd[NEG_X]->setChild( 1, _ed[6].get() ); 00272 _fd[NEG_X]->setChild( 2, _ed[5].get() ); 00273 _fd[NEG_X]->setChild( 3, _ed[4].get() ); 00274 00275 _fd[NEG_Z]->setChild( 0, _ed[11].get() ); 00276 _fd[NEG_Z]->setChild( 1, _ed[10].get() ); 00277 _fd[NEG_Z]->setChild( 2, _ed[8].get() ); 00278 _fd[NEG_Z]->setChild( 3, _ed[7].get() ); 00279 00280 // seed the bouding spheres of the manifold diamonds: 00281 for( unsigned short f=0; f<6; ++f ) 00282 _fd[f]->activate(); 00283 00284 for( unsigned short e=0; e<12; ++e ) 00285 _ed[e]->activate(); 00286 00287 // generate Level 3 (the first renderable quadtree decendants). 00288 seed( 3 ); 00289 00290 // hopefully, that's it! 00291 } 00292 00293 00294 osg::Vec3d 00295 CubeManifold::p( double x, double y, double z ) const 00296 { 00297 osg::Vec3d v( x, y, z ); 00298 return v; 00299 } 00300 00301 static bool 00302 toLonLatRad( const osg::Vec3d& coord, osg::Vec3d& out_lonLat ) 00303 { 00304 double lat, lon; 00305 00306 // normalize all coordinates into the [0..1] range: 00307 double x = (1.0+coord.x())*0.5; 00308 double y = (1.0+coord.y())*0.5; 00309 double z = (1.0+coord.z())*0.5; 00310 00311 // now convert into lat/long; this is different for each face: 00312 00313 if ( coord.x() == 1.0 ) // positive X ( 0 <= lon <= 90, -45 <= lat <= 45 ) 00314 { 00315 if ( !osgEarth::CubeUtils::faceCoordsToLatLon( y, z, 2, lat, lon ) ) 00316 OE_WARN << LC << "+X: fc2ll failed" << std::endl; 00317 } 00318 else if ( coord.x() == -1.0 ) // negative X ( -180 <= lon <= -90, -45 <= lat <= 45 ) 00319 { 00320 if ( !osgEarth::CubeUtils::faceCoordsToLatLon( 1.0-y, z, 0, lat, lon ) ) 00321 OE_WARN << LC << "-X: fc2ll failed" << std::endl; 00322 } 00323 else if ( coord.y() == 1.0 ) // positive Y ( 90 <= lon <= 180, -45 <= lat <= 45 ) 00324 { 00325 if ( !osgEarth::CubeUtils::faceCoordsToLatLon( 1.0-x, z, 3, lat, lon ) ) 00326 OE_WARN << LC << "+Y: fc2ll failed" << std::endl; 00327 } 00328 else if ( coord.y() == -1.0 ) // negative Y ( -90 <= lon <= 0, -45 <= lat <= 45 ) 00329 { 00330 if ( !osgEarth::CubeUtils::faceCoordsToLatLon( x, z, 1, lat, lon ) ) 00331 OE_WARN << LC << "-Y: fc2ll failed" << std::endl; 00332 } 00333 else if ( coord.z() == 1.0 ) // positive Z ( -180 <= lon < 180, 45 <= lat <= 90 ) 00334 { 00335 if ( !osgEarth::CubeUtils::faceCoordsToLatLon( 1.0-y, x, 4, lat, lon ) ) 00336 OE_WARN << LC << "+Z: fc2ll failed" << std::endl; 00337 } 00338 else //if ( coord.z() == -1.0 ) // negative Z ( -180 <= lon < 180, -90 <= lat <= -45 ) 00339 { 00340 if ( !osgEarth::CubeUtils::faceCoordsToLatLon( x, 1.0-y, 5, lat, lon ) ) 00341 OE_WARN << LC << "-Z: fc2ll failed" << std::endl; 00342 } 00343 00344 out_lonLat.x() = osg::DegreesToRadians( lon ); 00345 out_lonLat.y() = osg::DegreesToRadians( lat ); 00346 out_lonLat.z() = 0.0; 00347 00348 return true; 00349 } 00350 00351 00352 osg::Vec3d 00353 CubeManifold::midpoint( const osg::Vec3d& p0, const osg::Vec3d& p1 ) const 00354 { 00355 return (p0+p1)*0.5; 00356 } 00357 00358 MeshNode 00359 CubeManifold::createNode( const osg::Vec3d& manCoord ) const 00360 { 00361 MeshNode node; 00362 00363 node._manifoldCoord = manCoord; 00364 00365 toLonLatRad( manCoord, node._geodeticCoord ); // our manifold coords are already geodetic 00366 00367 osg::Matrixd local2world; 00368 _ellipsoid->computeLocalToWorldTransformFromLatLongHeight( 00369 node._geodeticCoord.y(), node._geodeticCoord.x(), node._geodeticCoord.z(), 00370 local2world ); 00371 00372 node._vertex = local2world.getTrans(); 00373 00374 node._normal = node._vertex; 00375 node._normal.normalize(); 00376 //node._normal = _ellipsoid->computeLocalUpVector( 00377 // node._vertex.x(), node._vertex.y(), node._vertex.z() ); 00378 00379 node._geodeticRot = local2world.getRotate(); 00380 //OE_INFO << LC 00381 // << "ROT: x=" << node._geodeticRot.x() << ", y=" << node._geodeticRot.y() 00382 // << ", z=" << node._geodeticRot.z() << ", w=" << node._geodeticRot.w() 00383 // << std::endl; 00384 00385 return node; 00386 } 00387 00388 osg::BoundingSphere 00389 CubeManifold::initialBound() const 00390 { 00391 return osg::BoundingSphere( osg::Vec3d(0,0,0), _ellipsoid->getRadiusEquator() * 1.2 ); 00392 //return osg::BoundingSphere( osg::Vec3d(0,0,0), 2.0 ); 00393 } 00394 00395 void 00396 CubeManifold::seed( Level maxLevel ) 00397 { 00398 for( unsigned short e=0; e<12; ++e ) 00399 { 00400 _ed[e]->seed( maxLevel ); 00401 } 00402 } 00403 00404 void 00405 CubeManifold::cull( osgUtil::CullVisitor* cv ) 00406 { 00407 for( unsigned short e=0; e<12; ++e ) 00408 { 00409 _ed[e]->cull( cv ); 00410 } 00411 }