From 6a76810c110a3f74478230fcb504e6591d396900 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 15 Jan 2004 21:07:34 +0000 Subject: [PATCH] Added automatic generation of LOD levels with destination graph --- examples/osgdem/DataSet.cpp | 337 ++++++++++++++++++++---------------- examples/osgdem/DataSet.h | 40 ++++- examples/osgdem/osgdem.cpp | 4 +- 3 files changed, 223 insertions(+), 158 deletions(-) diff --git a/examples/osgdem/DataSet.cpp b/examples/osgdem/DataSet.cpp index 08bbec670..ee86c6b8e 100644 --- a/examples/osgdem/DataSet.cpp +++ b/examples/osgdem/DataSet.cpp @@ -26,6 +26,8 @@ #include "cpl_string.h" #include +#include + DataSet::SourceData* DataSet::SourceData::readData(Source* source) { if (!source) return 0; @@ -195,20 +197,26 @@ osg::BoundingBox DataSet::SourceData::getExtents(const osgTerrain::CoordinateSys return _extents; } -DataSet::SpatialProperties DataSet::SourceData::computeSpatialProperties(osgTerrain::CoordinateSystem* cs) const +const DataSet::SpatialProperties& DataSet::SourceData::computeSpatialProperties(osgTerrain::CoordinateSystem* cs) const { if (_cs==cs) return *this; if (_cs.valid() && cs) { if (*_cs == *cs) return *this; + // check to see it exists in the _spatialPropertiesMap first. + SpatialPropertiesMap::const_iterator itr = _spatialPropertiesMap.find(cs); + if (itr!=_spatialPropertiesMap.end()) return itr->second; + if (_gdalDataSet) { //std::cout<<"Projecting bounding volume for "<<_source->getFileName()<_resX); minResY = osg::minimum(minResY,itr->_resY); - maxResX = osg::minimum(maxResX,itr->_resX); - maxResY = osg::minimum(maxResY,itr->_resY); + maxResX = osg::maximum(maxResX,itr->_resX); + maxResY = osg::maximum(maxResY,itr->_resY); } double currResX = minResX; @@ -921,11 +929,11 @@ void DataSet::DestinationTile::allocate() _terrain->_heightField->setXInterval(dem_dx); _terrain->_heightField->setYInterval(dem_dy); - float xMax = _terrain->_heightField->getOrigin().x()+_terrain->_heightField->getXInterval()*(float)(dem_numColumns-1); - std::cout<<"ErrorX = "<_heightField->getOrigin().x()+_terrain->_heightField->getXInterval()*(float)(dem_numColumns-1); + //std::cout<<"ErrorX = "<_heightField->getOrigin().y()+_terrain->_heightField->getYInterval()*(float)(dem_numRows-1); - std::cout<<"ErrorY = "<_heightField->getOrigin().y()+_terrain->_heightField->getYInterval()*(float)(dem_numRows-1); + //std::cout<<"ErrorY = "<_image.valid()) { std::string imageName(_name+".rgb"); + std::cout<<"Writing out imagery to "<_image->setFileName(imageName.c_str()); osgDB::writeImageFile(*_imagery->_image,_imagery->_image->getFileName().c_str()); @@ -1335,17 +1344,20 @@ osg::Node* DataSet::DestinationTile::createScene() } else { + std::cout<<"**** No terrain to build tile from, will need to create some fallback ****"<getSourceData(); if (data) { + std::cout<<"SourceData::read() "<read(*_imagery); if (_terrain.valid()) data->read(*_terrain); } @@ -1357,10 +1369,10 @@ void DataSet::DestinationTile::addRequiredResolutions(CompositeSource* sourceGra for(CompositeSource::source_iterator itr(sourceGraph);itr.valid();++itr) { Source* source = itr->get(); - - if (_imagery.valid() && source->getType()==Source::IMAGE) + + if (source->intersects(*this)) { - if (source->intersects(*_imagery)) + if (source->getType()==Source::IMAGE) { unsigned int numCols,numRows; double resX, resY; @@ -1369,10 +1381,8 @@ void DataSet::DestinationTile::addRequiredResolutions(CompositeSource* sourceGra source->addRequiredResolution(resX,resY); } } - } - if (_terrain.valid() && source->getType()==Source::HEIGHT_FIELD) - { - if (source->intersects(*_terrain)) + + if (source->getType()==Source::HEIGHT_FIELD) { unsigned int numCols,numRows; double resX, resY; @@ -1382,6 +1392,7 @@ void DataSet::DestinationTile::addRequiredResolutions(CompositeSource* sourceGra } } } + } } @@ -1407,6 +1418,8 @@ void DataSet::CompositeDestination::addRequiredResolutions(CompositeSource* sour void DataSet::CompositeDestination::readFrom(CompositeSource* sourceGraph) { + std::cout<<"CompositeDestination::readFrom() "< NodeList; - NodeList nodes; + if (_children.empty() && _tiles.size()==1) return _tiles.front()->createScene(); - // handle leaves + if (_tiles.empty() && _children.size()==1) return _children.front()->createScene(); + + + if (_type==GROUP) + { + osg::Group* group = new osg::Group; + for(TileList::iterator titr=_tiles.begin(); + titr!=_tiles.end(); + ++titr) + { + osg::Node* node = (*titr)->createScene(); + if (node) group->addChild(node); + } + + // handle chilren + for(ChildList::iterator citr=_children.begin(); + citr!=_children.end(); + ++citr) + { + osg::Node* node = (*citr)->createScene(); + if (node) group->addChild(node); + } + return group; + } + + // must be either a LOD or a PagedLOD + + typedef std::vector NodeList; + typedef std::map RangeNodeListMap; + RangeNodeListMap rangeNodeListMap; + + // insert local tiles into range map for(TileList::iterator titr=_tiles.begin(); titr!=_tiles.end(); ++titr) { osg::Node* node = (*titr)->createScene(); - if (node) nodes.push_back(node); + if (node) rangeNodeListMap[_maxVisibleDistance].push_back(node); } - + // handle chilren for(ChildList::iterator citr=_children.begin(); citr!=_children.end(); ++citr) { osg::Node* node = (*citr)->createScene(); - if (node) nodes.push_back(node); + if (node) rangeNodeListMap[(*citr)->_maxVisibleDistance].push_back(node); } - - if (nodes.empty()) return 0; - if (nodes.size()==1) return nodes.front(); - - osg::Group* group = new osg::Group; - for(NodeList::iterator nitr=nodes.begin(); - nitr!=nodes.end(); - ++nitr) - { - group->addChild(*nitr); - } - return group; + osg::PagedLOD* pagedLOD = (_type==PAGED_LOD) ? new osg::PagedLOD : 0; + osg::LOD* lod = (pagedLOD) ? pagedLOD : new osg::LOD; + + unsigned int childNum = 0; + for(RangeNodeListMap::reverse_iterator rnitr=rangeNodeListMap.rbegin(); + rnitr!=rangeNodeListMap.rend(); + ++rnitr) + { + float maxVisibleDistance = rnitr->first; + NodeList& nodeList = rnitr->second; + + if (childNum==0) + { + // by deafult make the first child have a very visible distance so its always seen + maxVisibleDistance = 1e8; + } + else + { + // set the previous child's minimum visible distance range + lod->setRange(childNum-1,maxVisibleDistance,lod->getMaxRange(childNum-1)); + } + + osg::Node* child = 0; + if (nodeList.size()==1) + { + child = nodeList.front(); + } + else if (nodeList.size()>1) + { + osg::Group* group = new osg::Group; + for(NodeList::iterator itr=nodeList.begin(); + itr!=nodeList.end(); + ++itr) + { + group->addChild(*itr); + } + child = group; + } + + if (child) + { + + if (pagedLOD) + { + std::cout<<"Need to set name of PagedLOD child"<addChild(child,0,maxVisibleDistance); + } + else + { + lod->addChild(child,0,maxVisibleDistance); + } + + ++childNum; + } + } + return lod; } /////////////////////////////////////////////////////////////////////////////// @@ -1534,20 +1621,32 @@ DataSet::CompositeDestination* DataSet::createDestinationGraph(osgTerrain::Coord unsigned int maxImageSize, unsigned int maxTerrainSize, unsigned int currentLevel, + unsigned int currentX, + unsigned int currentY, unsigned int maxNumLevels) { - DataSet::CompositeDestination* destinationGraph = new DataSet::CompositeDestination; + DataSet::CompositeDestination* destinationGraph = new DataSet::CompositeDestination(cs,extents); + + destinationGraph->_maxVisibleDistance = extents.radius()*5.0f; // first create the topmost tile + // create the name + std::ostringstream os; + os << _tileBasename << "_L"<_name = _tileBasename; + tile->_name = os.str(); tile->_cs = cs; tile->_extents = extents; + tile->_level = currentLevel; + tile->_X = currentX; + tile->_Y = currentY; tile->setMaximumImagerySize(maxImageSize,maxImageSize); tile->setMaximumTerrainSize(maxTerrainSize,maxTerrainSize); tile->computeMaximumSourceResolution(_sourceGraph.get()); + tile->allocate(); if (currentLevel>=maxNumLevels-1) { @@ -1556,6 +1655,7 @@ DataSet::CompositeDestination* DataSet::createDestinationGraph(osgTerrain::Coord } else { + destinationGraph->_type = LOD; destinationGraph->_tiles.push_back(tile); bool needToDivideX = false; @@ -1583,6 +1683,10 @@ DataSet::CompositeDestination* DataSet::createDestinationGraph(osgTerrain::Coord float xCenter = (extents.xMin()+extents.xMax())*0.5f; float yCenter = (extents.yMin()+extents.yMax())*0.5f; + + unsigned int newLevel = currentLevel+1; + unsigned int newX = currentX*2; + unsigned int newY = currentY*2; if (needToDivideX && needToDivideY) { @@ -1597,29 +1701,48 @@ DataSet::CompositeDestination* DataSet::createDestinationGraph(osgTerrain::Coord bottom_left, maxImageSize, maxTerrainSize, - currentLevel+1, + newLevel, + newX, + newY, maxNumLevels)); destinationGraph->_children.push_back(createDestinationGraph(cs, - bottom_left, + bottom_right, maxImageSize, maxTerrainSize, - currentLevel+1, + newLevel, + newX+1, + newY, maxNumLevels)); destinationGraph->_children.push_back(createDestinationGraph(cs, - bottom_left, + top_left, maxImageSize, maxTerrainSize, - currentLevel+1, + newLevel, + newX, + newY+1, maxNumLevels)); destinationGraph->_children.push_back(createDestinationGraph(cs, - bottom_left, + top_right, maxImageSize, maxTerrainSize, - currentLevel+1, + newLevel, + newX+1, + newY+1, maxNumLevels)); + + // Set all there max distance to the same value to ensure the same LOD bining. + float cutOffDistance = destinationGraph->_maxVisibleDistance*0.5f; + + for(CompositeDestination::ChildList::iterator citr=destinationGraph->_children.begin(); + citr!=destinationGraph->_children.end(); + ++citr) + { + (*citr)->_maxVisibleDistance = cutOffDistance; + } + } else if (needToDivideX) @@ -1637,9 +1760,22 @@ DataSet::CompositeDestination* DataSet::createDestinationGraph(osgTerrain::Coord } return destinationGraph; + +#if 0 + // now get each tile to point to each other. + top_left_tile->setNeighbours(0,0,bottom_left_tile,bottom_right_tile,top_right_tile,0,0,0); + top_right_tile->setNeighbours(top_left_tile,bottom_left_tile,bottom_right_tile,0,0,0,0,0); + bottom_left_tile->setNeighbours(0,0,0,0,bottom_right_tile,top_right_tile,top_left_tile,0); + bottom_right_tile->setNeighbours(bottom_left_tile,0,0,0,0,0,top_right_tile,top_left_tile); + + top_left_tile->checkNeighbouringTiles(); + top_right_tile->checkNeighbouringTiles(); + bottom_left_tile->checkNeighbouringTiles(); + bottom_right_tile->checkNeighbouringTiles(); +#endif } -void DataSet::computeDestinationGraphFromSources() +void DataSet::computeDestinationGraphFromSources(unsigned int numLevels) { // ensure we have a valid coordinate system @@ -1673,122 +1809,21 @@ void DataSet::computeDestinationGraphFromSources() // then create the destinate graph accordingly. -#if 1 unsigned int imageSize = 256; - unsigned int terrainSize = 256; - unsigned int numLevels = 5; + unsigned int terrainSize = 64; _destinationGraph = createDestinationGraph(_coordinateSystem.get(), extents, imageSize, terrainSize, 0, + 0, + 0, numLevels); -#else - _destinationGraph = new CompositeDestination; - _destinationGraph->_cs = _coordinateSystem; - _destinationGraph->_extents = extents; - - bool singleTile = false; - if (singleTile) - { - int imageSize = 4096; - int terrainSize = 1024; - - DestinationTile* tile = new DestinationTile; - tile->_name = _tileBasename; - tile->_cs = _destinationGraph->_cs; - tile->_extents = _destinationGraph->_extents; - tile->setMaximumImagerySize(imageSize,imageSize); - tile->setMaximumTerrainSize(terrainSize,terrainSize); - tile->computeMaximumSourceResolution(_sourceGraph.get()); - tile->allocate(); - _destinationGraph->_tiles.push_back(tile); - } - else - { - - - float xCenter = (extents.xMin()+extents.xMax())*0.5f; - float yCenter = (extents.yMin()+extents.yMax())*0.5f; - - - int imageSize = 2048; - int terrainSize = 512; - - DestinationTile* top_left_tile = 0; - DestinationTile* top_right_tile = 0; - DestinationTile* bottom_left_tile = 0; - DestinationTile* bottom_right_tile = 0; - - { - DestinationTile* tile = new DestinationTile; - tile->_name = _tileBasename+"_0"; - tile->_cs = _destinationGraph->_cs; - tile->_extents.set(extents.xMin(),extents.yMin(),extents.zMin(),xCenter,yCenter,extents.zMax()); - tile->setMaximumImagerySize(imageSize,imageSize); - tile->setMaximumTerrainSize(terrainSize,terrainSize); - tile->computeMaximumSourceResolution(_sourceGraph.get()); - tile->allocate(); - _destinationGraph->_tiles.push_back(tile); - bottom_left_tile = tile; - } - - { - DestinationTile* tile = new DestinationTile; - tile->_name = _tileBasename+"_1"; - tile->_cs = _destinationGraph->_cs; - tile->_extents.set(xCenter,extents.yMin(),extents.zMin(),extents.xMax(),yCenter,extents.zMax()); - tile->setMaximumImagerySize(imageSize,imageSize); - tile->setMaximumTerrainSize(terrainSize,terrainSize); - tile->computeMaximumSourceResolution(_sourceGraph.get()); - tile->allocate(); - _destinationGraph->_tiles.push_back(tile); - bottom_right_tile = tile; - } - - { - DestinationTile* tile = new DestinationTile; - tile->_name = _tileBasename+"_2"; - tile->_cs = _destinationGraph->_cs; - tile->_extents.set(extents.xMin(),yCenter,extents.zMin(),xCenter,extents.yMax(),extents.zMax()); - tile->setMaximumImagerySize(imageSize,imageSize); - tile->setMaximumTerrainSize(terrainSize,terrainSize); - tile->computeMaximumSourceResolution(_sourceGraph.get()); - tile->allocate(); - _destinationGraph->_tiles.push_back(tile); - top_left_tile = tile; - } - - { - DestinationTile* tile = new DestinationTile; - tile->_name = _tileBasename+"_3"; - tile->_cs = _destinationGraph->_cs; - tile->_extents.set(xCenter,yCenter,extents.zMin(),extents.xMax(),extents.yMax(),extents.zMax()); - tile->setMaximumImagerySize(imageSize,imageSize); - tile->setMaximumTerrainSize(terrainSize,terrainSize); - tile->computeMaximumSourceResolution(_sourceGraph.get()); - tile->allocate(); - _destinationGraph->_tiles.push_back(tile); - top_right_tile = tile; - } - - // now get each tile to point to each other. - top_left_tile->setNeighbours(0,0,bottom_left_tile,bottom_right_tile,top_right_tile,0,0,0); - top_right_tile->setNeighbours(top_left_tile,bottom_left_tile,bottom_right_tile,0,0,0,0,0); - bottom_left_tile->setNeighbours(0,0,0,0,bottom_right_tile,top_right_tile,top_left_tile,0); - bottom_right_tile->setNeighbours(bottom_left_tile,0,0,0,0,0,top_right_tile,top_left_tile); - - top_left_tile->checkNeighbouringTiles(); - top_right_tile->checkNeighbouringTiles(); - bottom_left_tile->checkNeighbouringTiles(); - bottom_right_tile->checkNeighbouringTiles(); - } -#endif } @@ -1872,6 +1907,7 @@ void DataSet::updateSourcesForDestinationGraphNeeds() } +#if 1 // do standardisation of coordinates systems. // do any reprojection if required. { @@ -1890,6 +1926,7 @@ void DataSet::updateSourcesForDestinationGraphNeeds() } } } +#endif // do sampling of data to required values. { @@ -1938,12 +1975,12 @@ void DataSet::populateDestinationGraphFromSources() } -void DataSet::createDestination() +void DataSet::createDestination(unsigned int numLevels) { std::cout<<"new DataSet::createDestination()"< _model; GDALDataset* _gdalDataSet; + typedef std::map SpatialPropertiesMap; + mutable SpatialPropertiesMap _spatialPropertiesMap; + + }; @@ -259,7 +269,8 @@ class DataSet : public osg::Referenced enum CompositeType { GROUP, - LEVEL_OF_DETAIL + LOD, + PAGED_LOD }; class CompositeSource : public osg::Referenced, public SpatialProperties @@ -681,13 +692,26 @@ class DataSet : public osg::Referenced unsigned int _terrain_maxNumRows; float _terrain_maxSourceResolutionX; float _terrain_maxSourceResolutionY; + + unsigned int _level; + unsigned int _X; + unsigned int _Y; }; class CompositeDestination : public osg::Referenced, public SpatialProperties { - public: - + public: + + CompositeDestination(): + _type(GROUP), + _maxVisibleDistance(FLT_MAX) {} + + CompositeDestination(osgTerrain::CoordinateSystem* cs, const osg::BoundingBox& extents): + SpatialProperties(cs,extents), + _type(GROUP), + _maxVisibleDistance(FLT_MAX) {} + void addRequiredResolutions(CompositeSource* sourceGraph); void readFrom(CompositeSource* sourceGraph); @@ -702,6 +726,8 @@ class DataSet : public osg::Referenced CompositeType _type; TileList _tiles; ChildList _children; + float _maxVisibleDistance; + }; public: @@ -726,14 +752,16 @@ class DataSet : public osg::Referenced unsigned int maxImageSize, unsigned int maxTerrainSize, unsigned int currentLevel, + unsigned int currentX, + unsigned int currentY, unsigned int maxNumLevels); - void computeDestinationGraphFromSources(); + void computeDestinationGraphFromSources(unsigned int numLevels); void updateSourcesForDestinationGraphNeeds(); void populateDestinationGraphFromSources(); - void createDestination(); + void createDestination(unsigned int numLevels); void writeDestination(const std::string& filename); diff --git a/examples/osgdem/osgdem.cpp b/examples/osgdem/osgdem.cpp index 5f6b053e0..1c8e53975 100644 --- a/examples/osgdem/osgdem.cpp +++ b/examples/osgdem/osgdem.cpp @@ -96,7 +96,7 @@ int main( int argc, char **argv ) } - float numLevels; + float numLevels = 6.0f; while (arguments.read("-l",numLevels)) {} float verticalScale; @@ -122,7 +122,7 @@ int main( int argc, char **argv ) dataset->loadSources(); - dataset->createDestination(); + dataset->createDestination((unsigned int)numLevels); dataset->writeDestination(outputFileName);