"There was a typo in "int setNotifyOffset()", appear to be a getter => "int getNotifyOffset()". Then I have added a switch to create GDALTermProgress only when the current notify level + local offset permit message display. In fact, if the offset is set to 0 and the notify level is at the default, DataSet is quiet but for the GDALTermProgress. That is quite disturbing since you think the progress is related to the complete processing but it is actually only related to the GDAL Warp."
1272 lines
47 KiB
C++
1272 lines
47 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
|
|
*
|
|
* This library is open source and may be redistributed and/or modified under
|
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
|
* (at your option) any later version. The full license is in LICENSE file
|
|
* included with this distribution, and on the openscenegraph.org website.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* OpenSceneGraph Public License for more details.
|
|
*/
|
|
|
|
#ifdef WIN32
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Disable unavoidable warning messages:
|
|
//
|
|
// C4503 - decorated name length exceeded, name was truncated
|
|
//
|
|
#pragma warning(disable : 4503)
|
|
|
|
#endif // WIN32
|
|
|
|
#ifndef DATASET_H
|
|
#define DATASET_H 1
|
|
|
|
#include <osg/BoundingSphere>
|
|
#include <osg/Node>
|
|
#include <osg/Matrixd>
|
|
#include <osg/Image>
|
|
#include <osg/Shape>
|
|
#include <osg/CoordinateSystemNode>
|
|
#include <osg/State>
|
|
|
|
#include <osgDB/Archive>
|
|
|
|
#include <set>
|
|
|
|
#include <osgTerrain/Export>
|
|
|
|
// forward declare so we can avoid tieing osgTerrain to GDAL.
|
|
class GDALDataset;
|
|
|
|
namespace osgTerrain
|
|
{
|
|
|
|
#define MAXIMUM_NUMBER_OF_LEVELS 30
|
|
|
|
class GeospatialExtents
|
|
{
|
|
public:
|
|
|
|
osg::Vec2d _min;
|
|
osg::Vec2d _max;
|
|
|
|
inline GeospatialExtents() :
|
|
_min(DBL_MAX,DBL_MAX),
|
|
_max(DBL_MIN,DBL_MIN) {}
|
|
|
|
inline GeospatialExtents(double xmin, double ymin, double xmax, double ymax) :
|
|
_min(xmin, ymin),
|
|
_max(xmax, ymax){}
|
|
|
|
inline double& xMin() { return _min.x(); }
|
|
inline double xMin() const { return _min.x(); }
|
|
|
|
inline double& yMin() { return _min.y(); }
|
|
inline double yMin() const { return _min.y(); }
|
|
|
|
inline double& xMax() { return _max.x(); }
|
|
inline double xMax() const { return _max.x(); }
|
|
|
|
inline double& yMax() { return _max.y(); }
|
|
inline double yMax() const { return _max.y(); }
|
|
|
|
inline void init()
|
|
{
|
|
_min.set(DBL_MAX,DBL_MAX);
|
|
_max.set(-DBL_MAX,-DBL_MAX);
|
|
}
|
|
|
|
inline bool valid() const
|
|
{
|
|
return _max.x()>=_min.x() && _max.y()>=_min.y();
|
|
}
|
|
|
|
inline double radius() const
|
|
{
|
|
return sqrt((radius2()));
|
|
}
|
|
|
|
inline double radius2() const
|
|
{
|
|
return 0.25f*((_max-_min).length2());
|
|
}
|
|
|
|
GeospatialExtents intersect(const GeospatialExtents& e) const
|
|
{
|
|
return GeospatialExtents(osg::maximum(xMin(),e.xMin()),osg::maximum(yMin(),e.yMin()),
|
|
osg::minimum(xMax(),e.xMax()),osg::minimum(yMax(),e.yMax()));
|
|
}
|
|
|
|
/** Return true if this bounding box intersects the specified bounding box. */
|
|
bool intersects(const GeospatialExtents& bb) const
|
|
{
|
|
return osg::maximum(xMin(),bb.xMin()) <= osg::minimum(xMax(),bb.xMax()) &&
|
|
osg::maximum(yMin(),bb.yMin()) <= osg::minimum(yMax(),bb.yMax());
|
|
}
|
|
|
|
void expandBy(const osg::BoundingSphere& sh)
|
|
{
|
|
if (!sh.valid()) return;
|
|
|
|
if(sh._center.x()-sh._radius<_min.x()) _min.x() = sh._center.x()-sh._radius;
|
|
if(sh._center.x()+sh._radius>_max.x()) _max.x() = sh._center.x()+sh._radius;
|
|
|
|
if(sh._center.y()-sh._radius<_min.y()) _min.y() = sh._center.y()-sh._radius;
|
|
if(sh._center.y()+sh._radius>_max.y()) _max.y() = sh._center.y()+sh._radius;
|
|
}
|
|
|
|
inline void expandBy(const osg::Vec3& v)
|
|
{
|
|
if(v.x()<_min.x()) _min.x() = v.x();
|
|
if(v.x()>_max.x()) _max.x() = v.x();
|
|
|
|
if(v.y()<_min.y()) _min.y() = v.y();
|
|
if(v.y()>_max.y()) _max.y() = v.y();
|
|
}
|
|
|
|
void expandBy(const GeospatialExtents& e)
|
|
{
|
|
if (!e.valid()) return;
|
|
|
|
if(e._min.x()<_min.x()) _min.x() = e._min.x();
|
|
if(e._max.x()>_max.x()) _max.x() = e._max.x();
|
|
|
|
if(e._min.y()<_min.y()) _min.y() = e._min.y();
|
|
if(e._max.y()>_max.y()) _max.y() = e._max.y();
|
|
}
|
|
};
|
|
|
|
|
|
|
|
class OSGTERRAIN_EXPORT DataSet : public osg::Referenced
|
|
{
|
|
public:
|
|
|
|
static std::string coordinateSystemStringToWTK(const std::string& coordinateSystem);
|
|
|
|
class Source;
|
|
|
|
struct SpatialProperties
|
|
{
|
|
SpatialProperties():
|
|
_numValuesX(0),
|
|
_numValuesY(0),
|
|
_numValuesZ(0) {}
|
|
|
|
SpatialProperties(const SpatialProperties& sp):
|
|
_cs(sp._cs),
|
|
_geoTransform(sp._geoTransform),
|
|
_extents(sp._extents),
|
|
_numValuesX(sp._numValuesX),
|
|
_numValuesY(sp._numValuesY),
|
|
_numValuesZ(sp._numValuesZ) {}
|
|
|
|
SpatialProperties(osg::CoordinateSystemNode* cs, const GeospatialExtents& extents):
|
|
_cs(cs),
|
|
_extents(extents),
|
|
_numValuesX(0),
|
|
_numValuesY(0),
|
|
_numValuesZ(0) {}
|
|
|
|
inline SpatialProperties& assignSpatialProperties(const SpatialProperties& sp)
|
|
{
|
|
if (&sp==this) return *this;
|
|
|
|
_cs = sp._cs;
|
|
_geoTransform = sp._geoTransform;
|
|
_extents = sp._extents;
|
|
_numValuesX = sp._numValuesX;
|
|
_numValuesY = sp._numValuesY;
|
|
_numValuesZ = sp._numValuesZ;
|
|
|
|
return *this;
|
|
}
|
|
|
|
void computeExtents()
|
|
{
|
|
_extents.init();
|
|
_extents.expandBy( osg::Vec3(0.0,0.0,0.0)*_geoTransform);
|
|
_extents.expandBy( osg::Vec3(_numValuesX,_numValuesY,0.0)*_geoTransform);
|
|
}
|
|
|
|
osg::ref_ptr<osg::CoordinateSystemNode> _cs;
|
|
osg::Matrixd _geoTransform;
|
|
GeospatialExtents _extents;
|
|
unsigned int _numValuesX;
|
|
unsigned int _numValuesY;
|
|
unsigned int _numValuesZ;
|
|
};
|
|
|
|
struct DestinationData : public osg::Referenced, SpatialProperties
|
|
{
|
|
|
|
DestinationData(DataSet* dataSet):
|
|
_dataSet(dataSet),
|
|
_minDistance(0.0),
|
|
_maxDistance(FLT_MAX) {}
|
|
|
|
|
|
typedef std::vector< osg::ref_ptr<osg::Image> > ImageList;
|
|
typedef std::vector< osg::ref_ptr<osg::Node> > ModelList;
|
|
|
|
DataSet* _dataSet;
|
|
|
|
float _minDistance;
|
|
float _maxDistance;
|
|
|
|
|
|
osg::ref_ptr<osg::Image> _image;
|
|
osg::ref_ptr<osg::HeightField> _heightField;
|
|
ModelList _models;
|
|
};
|
|
|
|
struct OSGTERRAIN_EXPORT SourceData : public osg::Referenced, public SpatialProperties
|
|
{
|
|
|
|
SourceData(Source* source=0):
|
|
_source(source),
|
|
_hasGCPs(false),
|
|
_gdalDataset(0) {}
|
|
|
|
virtual ~SourceData();
|
|
|
|
static SourceData* readData(Source* source);
|
|
|
|
GeospatialExtents getExtents(const osg::CoordinateSystemNode* cs) const;
|
|
|
|
const SpatialProperties& computeSpatialProperties(const osg::CoordinateSystemNode* cs) const;
|
|
|
|
bool intersects(const SpatialProperties& sp) const;
|
|
|
|
void read(DestinationData& destination);
|
|
|
|
virtual void readImage(DestinationData& destination);
|
|
virtual void readHeightField(DestinationData& destination);
|
|
virtual void readModels(DestinationData& destination);
|
|
|
|
Source* _source;
|
|
|
|
bool _hasGCPs;
|
|
|
|
osg::ref_ptr<osg::Node> _model;
|
|
GDALDataset* _gdalDataset;
|
|
|
|
typedef std::map<const osg::CoordinateSystemNode*,SpatialProperties> SpatialPropertiesMap;
|
|
mutable SpatialPropertiesMap _spatialPropertiesMap;
|
|
|
|
|
|
};
|
|
|
|
|
|
class OSGTERRAIN_EXPORT Source : public osg::Referenced, public SpatialProperties
|
|
{
|
|
public:
|
|
|
|
enum Type
|
|
{
|
|
IMAGE,
|
|
HEIGHT_FIELD,
|
|
MODEL
|
|
};
|
|
|
|
enum ParameterPolicy
|
|
{
|
|
PREFER_CONFIG_SETTINGS,
|
|
PREFER_CONFIG_SETTINGS_BUT_SCALE_BY_FILE_RESOLUTION,
|
|
PREFER_FILE_SETTINGS
|
|
};
|
|
|
|
Source():
|
|
_type(IMAGE),
|
|
_sortValue(0.0),
|
|
_temporaryFile(false),
|
|
_coordinateSystemPolicy(PREFER_FILE_SETTINGS),
|
|
_geoTransformPolicy(PREFER_FILE_SETTINGS),
|
|
_minLevel(0),
|
|
_maxLevel(MAXIMUM_NUMBER_OF_LEVELS),
|
|
_layer(0),
|
|
_gdalDataset(0)
|
|
{}
|
|
|
|
Source(Type type, const std::string& filename):
|
|
_type(type),
|
|
_sortValue(0.0),
|
|
_filename(filename),
|
|
_temporaryFile(false),
|
|
_coordinateSystemPolicy(PREFER_FILE_SETTINGS),
|
|
_geoTransformPolicy(PREFER_FILE_SETTINGS),
|
|
_minLevel(0),
|
|
_maxLevel(MAXIMUM_NUMBER_OF_LEVELS),
|
|
_layer(0),
|
|
_gdalDataset(0)
|
|
{}
|
|
|
|
void setSortValue(double s) { _sortValue = s; }
|
|
double getSortValue() const { return _sortValue; }
|
|
|
|
void setSortValueFromSourceDataResolution();
|
|
|
|
void setType(Type type) { _type = type; }
|
|
Type getType() const { return _type; }
|
|
|
|
void setFileName(const std::string& filename) { _filename = filename; }
|
|
const std::string& getFileName() const { return _filename; }
|
|
|
|
void setTemporaryFile(bool temporaryFile) { _temporaryFile = temporaryFile; }
|
|
bool getTemporaryFile() const { return _temporaryFile; }
|
|
|
|
void setGdalDataset(void* gdalDataset);
|
|
void* getGdalDataset();
|
|
const void* getGdalDataset() const;
|
|
|
|
void setCoordinateSystemPolicy(ParameterPolicy policy) { _coordinateSystemPolicy = policy; }
|
|
ParameterPolicy getCoordinateSystemPolicy() const { return _coordinateSystemPolicy; }
|
|
|
|
void setCoordinateSystem(const std::string& wellKnownText) { _cs = new osg::CoordinateSystemNode("WKT",wellKnownText); }
|
|
void setCoordinateSystem(osg::CoordinateSystemNode* cs) { _cs = cs; }
|
|
osg::CoordinateSystemNode* getCoordinateSystem() { return _cs.get(); }
|
|
|
|
|
|
void setGeoTransformPolicy(ParameterPolicy policy) { _geoTransformPolicy = policy; }
|
|
ParameterPolicy getGeoTransformPolicy() const { return _geoTransformPolicy; }
|
|
|
|
void setGeoTransform(osg::Matrixd& transform) { _geoTransform = transform; }
|
|
osg::Matrixd& getGeoTransform() { return _geoTransform; }
|
|
|
|
void setGeoTransformFromRange(double xMin, double xMax, double yMin, double yMax)
|
|
{
|
|
_geoTransform.makeIdentity();
|
|
_geoTransform(0,0) = xMax-xMin;
|
|
_geoTransform(3,0) = xMin;
|
|
|
|
_geoTransform(1,1) = yMax-yMin;
|
|
_geoTransform(3,1) = yMin;
|
|
}
|
|
|
|
|
|
void assignCoordinateSystemAndGeoTransformAccordingToParameterPolicy();
|
|
|
|
|
|
|
|
void setMinLevel(unsigned int minLevel) { _minLevel = minLevel; }
|
|
void setMaxLevel(unsigned int maxLevel) { _maxLevel = maxLevel; }
|
|
void setMinMaxLevel(unsigned int minLevel, unsigned int maxLevel) { _minLevel = minLevel; _maxLevel = maxLevel; }
|
|
|
|
unsigned int getMinLevel() const { return _minLevel; }
|
|
unsigned int getMaxLevel() const { return _maxLevel; }
|
|
|
|
void setLayer(unsigned int layer) { _layer = layer; }
|
|
unsigned int getLayer() const { return _layer; }
|
|
|
|
|
|
void setSourceData(SourceData* data) { _sourceData = data; if (_sourceData.valid()) _sourceData->_source = this; }
|
|
SourceData* getSourceData() { return _sourceData.get(); }
|
|
|
|
bool intersects(const SpatialProperties& sp) const
|
|
{
|
|
return _sourceData.valid()?_sourceData->intersects(sp):false;
|
|
}
|
|
|
|
void loadSourceData();
|
|
|
|
|
|
bool needReproject(const osg::CoordinateSystemNode* cs) const;
|
|
|
|
bool needReproject(const osg::CoordinateSystemNode* cs, double minResolution, double maxResolution) const;
|
|
|
|
Source* doReproject(const std::string& filename, osg::CoordinateSystemNode* cs, double targetResolution=0.0) const;
|
|
|
|
void buildOverviews();
|
|
|
|
|
|
struct ResolutionPair
|
|
{
|
|
ResolutionPair():
|
|
_resX(0.0),_resY(0.0) {}
|
|
|
|
ResolutionPair(double x,double y):
|
|
_resX(x),_resY(y) {}
|
|
|
|
bool operator < (const ResolutionPair& rhs) const
|
|
{
|
|
double minLHS = osg::minimum(_resX,_resY);
|
|
double minRHS = osg::minimum(rhs._resX,rhs._resY);
|
|
return minLHS<minRHS;
|
|
}
|
|
|
|
double _resX;
|
|
double _resY;
|
|
};
|
|
|
|
typedef std::vector<ResolutionPair> ResolutionList;
|
|
|
|
void addRequiredResolution(double resX, double resY) { _requiredResolutions.push_back(ResolutionPair(resX,resY)); }
|
|
|
|
void setRequiredResolutions(ResolutionList& resolutions) { _requiredResolutions = resolutions; }
|
|
|
|
ResolutionList& getRequiredResolutions() { return _requiredResolutions; }
|
|
|
|
const ResolutionList& getRequiredResolutions() const { return _requiredResolutions; }
|
|
|
|
void consolodateRequiredResolutions();
|
|
|
|
protected:
|
|
|
|
|
|
Type _type;
|
|
|
|
double _sortValue;
|
|
|
|
std::string _filename;
|
|
bool _temporaryFile;
|
|
|
|
ParameterPolicy _coordinateSystemPolicy;
|
|
ParameterPolicy _geoTransformPolicy;
|
|
|
|
unsigned int _minLevel;
|
|
unsigned int _maxLevel;
|
|
unsigned int _layer;
|
|
|
|
osg::ref_ptr<SourceData> _sourceData;
|
|
|
|
ResolutionList _requiredResolutions;
|
|
|
|
GDALDataset* _gdalDataset;
|
|
};
|
|
|
|
enum CompositeType
|
|
{
|
|
GROUP,
|
|
LOD,
|
|
PAGED_LOD
|
|
};
|
|
|
|
class OSGTERRAIN_EXPORT CompositeSource : public osg::Referenced, public SpatialProperties
|
|
{
|
|
public:
|
|
|
|
CompositeSource(CompositeType type=GROUP):_type(type) {};
|
|
|
|
typedef std::vector< osg::ref_ptr<Source> > SourceList;
|
|
typedef std::vector< osg::ref_ptr< CompositeSource> > ChildList;
|
|
|
|
void setType(CompositeType type) { _type = type; }
|
|
CompositeType getType() const { return _type; }
|
|
|
|
void setSortValueFromSourceDataResolution();
|
|
|
|
void sort();
|
|
|
|
class iterator
|
|
{
|
|
public:
|
|
|
|
enum IteratorMode
|
|
{
|
|
ACTIVE,
|
|
ALL
|
|
};
|
|
|
|
|
|
iterator(CompositeSource* composite=0,IteratorMode mode=ALL):
|
|
_iteratorMode(mode)
|
|
{
|
|
if (composite)
|
|
{
|
|
_positionStack.push_back(IteratorPosition(composite));
|
|
}
|
|
}
|
|
|
|
iterator(const iterator& rhs):
|
|
_positionStack(rhs._positionStack) {}
|
|
|
|
iterator& operator = (const iterator& rhs)
|
|
{
|
|
if (&rhs==this) return *this;
|
|
_positionStack = rhs._positionStack;
|
|
return *this;
|
|
}
|
|
|
|
bool operator == (const iterator& rhs) const
|
|
{
|
|
return _positionStack == rhs._positionStack;
|
|
}
|
|
|
|
bool operator != (const iterator& rhs) const
|
|
{
|
|
return _positionStack != rhs._positionStack;
|
|
}
|
|
|
|
bool valid() const
|
|
{
|
|
return !_positionStack.empty() && _positionStack.back().valid();
|
|
}
|
|
|
|
CompositeSource& operator *()
|
|
{
|
|
return *(valid()?_positionStack.back().current():0);
|
|
}
|
|
|
|
CompositeSource* operator ->()
|
|
{
|
|
return valid()?_positionStack.back().current():0;
|
|
}
|
|
|
|
const CompositeSource& operator *() const
|
|
{
|
|
return *(valid()?_positionStack.back().current():0);
|
|
}
|
|
|
|
const CompositeSource* operator ->() const
|
|
{
|
|
return valid()?_positionStack.back().current():0;
|
|
}
|
|
|
|
iterator& operator++()
|
|
{
|
|
advance();
|
|
return *this;
|
|
}
|
|
|
|
iterator operator++(int)
|
|
{
|
|
iterator tmp=*this;
|
|
advance();
|
|
return tmp;
|
|
}
|
|
|
|
bool advance()
|
|
{
|
|
if (_positionStack.empty()) return false;
|
|
|
|
// simple advance to the next source
|
|
if (_positionStack.back().advance())
|
|
{
|
|
if (_positionStack.back().current())
|
|
{
|
|
_positionStack.push_back(IteratorPosition(_positionStack.back().current()));
|
|
return advance();
|
|
}
|
|
}
|
|
|
|
_positionStack.pop_back();
|
|
return advance();
|
|
}
|
|
|
|
|
|
protected:
|
|
|
|
struct IteratorPosition
|
|
{
|
|
|
|
IteratorPosition(CompositeSource* composite):
|
|
_composite(composite),
|
|
_index(-1) {}
|
|
|
|
IteratorPosition(const IteratorPosition& rhs):
|
|
_composite(rhs._composite),
|
|
_index(rhs._index) {}
|
|
|
|
IteratorPosition& operator = (const IteratorPosition& rhs)
|
|
{
|
|
_composite = rhs._composite;
|
|
_index = rhs._index;
|
|
return *this;
|
|
}
|
|
|
|
bool operator == (const IteratorPosition& rhs) const
|
|
{
|
|
return _composite == rhs._composite && _index == rhs._index;
|
|
}
|
|
|
|
bool operator != (const IteratorPosition& rhs) const
|
|
{
|
|
return _composite != rhs._composite || _index != rhs._index;
|
|
}
|
|
|
|
CompositeSource* current()
|
|
{
|
|
if (_index==-1) return _composite;
|
|
else return (_index>=0 && _index < (int)_composite->_children.size())?_composite->_children[_index].get():0;
|
|
}
|
|
|
|
const CompositeSource* current() const
|
|
{
|
|
if (_index==-1) return _composite;
|
|
else return (_index>=0 && _index < (int)_composite->_children.size())?_composite->_children[_index].get():0;
|
|
}
|
|
|
|
bool valid() const
|
|
{
|
|
return _composite &&
|
|
_index < (int)_composite->_children.size();
|
|
}
|
|
|
|
inline bool advance()
|
|
{
|
|
return advanceToNextChild(*_composite,_index);
|
|
}
|
|
|
|
inline bool isActive(const CompositeSource& /*composite*/,int /*index*/)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
inline bool advanceToNextChild(CompositeSource& composite, int& index)
|
|
{
|
|
++index;
|
|
while (index<(int)composite._children.size())
|
|
{
|
|
if (isActive(composite,index)) return true;
|
|
++index;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
CompositeSource* _composite;
|
|
int _index;
|
|
};
|
|
|
|
typedef std::vector<IteratorPosition> PositionStack;
|
|
IteratorMode _iteratorMode;
|
|
PositionStack _positionStack;
|
|
};
|
|
|
|
|
|
template<class T>
|
|
class base_source_iterator
|
|
{
|
|
public:
|
|
|
|
|
|
base_source_iterator(CompositeSource* composite=0, T advancer=T()):
|
|
_advancer(advancer),
|
|
_compositeIterator(composite),
|
|
_sourceIndex(-1)
|
|
{
|
|
advance();
|
|
}
|
|
|
|
base_source_iterator(const base_source_iterator& rhs):
|
|
_advancer(rhs._advancer),
|
|
_compositeIterator(rhs._compositeIterator),
|
|
_sourceIndex(rhs._sourceIndex) {}
|
|
|
|
base_source_iterator& operator = (const base_source_iterator& rhs)
|
|
{
|
|
if (&rhs==this) return *this;
|
|
_advancer = rhs._advancer;
|
|
_compositeIterator = rhs._compositeIterator;
|
|
_sourceIndex = rhs._sourceIndex;
|
|
}
|
|
|
|
bool operator == (const base_source_iterator& rhs) const
|
|
{
|
|
return _compositeIterator == rhs._compositeIterator &&
|
|
_sourceIndex == rhs._sourceIndex;
|
|
}
|
|
|
|
bool operator != (const base_source_iterator& rhs) const
|
|
{
|
|
return _compositeIterator != rhs._compositeIterator ||
|
|
_sourceIndex != rhs._sourceIndex;
|
|
}
|
|
|
|
bool valid() const
|
|
{
|
|
return _compositeIterator.valid() && _sourceIndex < (int)_compositeIterator->_sourceList.size();
|
|
}
|
|
|
|
osg::ref_ptr<Source>& operator *()
|
|
{
|
|
return valid()?_compositeIterator->_sourceList[_sourceIndex]:_nullSource;
|
|
}
|
|
|
|
osg::ref_ptr<Source>* operator ->()
|
|
{
|
|
return &(valid()?_compositeIterator->_sourceList[_sourceIndex]:_nullSource);
|
|
}
|
|
|
|
base_source_iterator& operator++()
|
|
{
|
|
advance();
|
|
return *this;
|
|
}
|
|
|
|
base_source_iterator operator++(int)
|
|
{
|
|
base_source_iterator tmp=*this;
|
|
advance();
|
|
return tmp;
|
|
}
|
|
|
|
bool advance()
|
|
{
|
|
if (!_compositeIterator.valid()) return false;
|
|
|
|
if (_advancer.advanceToNextSource(*_compositeIterator,_sourceIndex)) return true;
|
|
|
|
// at end of current CompositeSource, so need to advance to new one.
|
|
_sourceIndex = -1;
|
|
++_compositeIterator;
|
|
return advance();
|
|
}
|
|
|
|
protected:
|
|
|
|
T _advancer;
|
|
iterator _compositeIterator;
|
|
int _sourceIndex;
|
|
osg::ref_ptr<Source> _nullSource;
|
|
|
|
};
|
|
|
|
struct DefaultSourceAdvancer
|
|
{
|
|
DefaultSourceAdvancer() {}
|
|
|
|
bool isActive(const CompositeSource& /*composite*/,int /*index*/)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
inline bool advanceToNextSource(const CompositeSource& composite, int& index)
|
|
{
|
|
return ++index<(int)composite._sourceList.size();
|
|
}
|
|
};
|
|
|
|
struct LODSourceAdvancer
|
|
{
|
|
LODSourceAdvancer(float targetResolution=0.0f):
|
|
_targetResolution(targetResolution) {}
|
|
|
|
inline bool advanceToNextSource(const CompositeSource& composite, int& index)
|
|
{
|
|
if (composite.getType()==GROUP)
|
|
{
|
|
return (++index<(int)composite._sourceList.size());
|
|
}
|
|
else
|
|
{
|
|
if (composite._sourceList.empty()) return false;
|
|
if (index!=-1) return false; // we've already traversed this composite, only ever one valid LOD.
|
|
|
|
// find source with resolution closest to target
|
|
int foundIndex = 0;
|
|
float closestResolution = fabsf(composite._sourceList[0]->getSortValue()-_targetResolution);
|
|
for(int i=1;i<(int)composite._sourceList.size();++i)
|
|
{
|
|
float delta = fabsf(composite._sourceList[i]->getSortValue()-_targetResolution);
|
|
if (delta<closestResolution)
|
|
{
|
|
foundIndex = i;
|
|
closestResolution = delta;
|
|
}
|
|
}
|
|
if (foundIndex==index) return false;
|
|
index = foundIndex;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
float _targetResolution;
|
|
};
|
|
|
|
typedef base_source_iterator<DefaultSourceAdvancer> source_iterator;
|
|
typedef base_source_iterator<LODSourceAdvancer> source_lod_iterator;
|
|
|
|
CompositeType _type;
|
|
SourceList _sourceList;
|
|
ChildList _children;
|
|
};
|
|
|
|
|
|
class OSGTERRAIN_EXPORT DestinationTile : public osg::Referenced, public SpatialProperties
|
|
{
|
|
public:
|
|
|
|
|
|
enum Position
|
|
{
|
|
LEFT = 0,
|
|
LEFT_BELOW = 1,
|
|
BELOW = 2,
|
|
BELOW_RIGHT = 3,
|
|
RIGHT = 4,
|
|
RIGHT_ABOVE = 5,
|
|
ABOVE = 6,
|
|
ABOVE_LEFT = 7,
|
|
NUMBER_OF_POSITIONS = 8
|
|
};
|
|
|
|
|
|
DestinationTile();
|
|
|
|
void computeNeighboursFromQuadMap();
|
|
|
|
void setNeighbours(DestinationTile* left, DestinationTile* left_below,
|
|
DestinationTile* below, DestinationTile* below_right,
|
|
DestinationTile* right, DestinationTile* right_above,
|
|
DestinationTile* above, DestinationTile* above_left);
|
|
|
|
void checkNeighbouringTiles();
|
|
|
|
void setMaximumImagerySize(unsigned int maxNumColumns,unsigned int maxNumRows)
|
|
{
|
|
_imagery_maxNumColumns = maxNumColumns;
|
|
_imagery_maxNumRows = maxNumRows;
|
|
}
|
|
|
|
void setMaximumTerrainSize(unsigned int maxNumColumns,unsigned int maxNumRows)
|
|
{
|
|
_terrain_maxNumColumns = maxNumColumns;
|
|
_terrain_maxNumRows = maxNumRows;
|
|
}
|
|
|
|
void computeMaximumSourceResolution(CompositeSource* sourceGraph);
|
|
|
|
bool computeImageResolution(unsigned int layer, unsigned int& numColumns, unsigned int& numRows, double& resX, double& resY);
|
|
bool computeTerrainResolution(unsigned int& numColumns, unsigned int& numRows, double& resX, double& resY);
|
|
|
|
void allocate();
|
|
|
|
void addRequiredResolutions(CompositeSource* sourceGraph);
|
|
|
|
void readFrom(CompositeSource* sourceGraph);
|
|
|
|
void allocateEdgeNormals();
|
|
|
|
void equalizeCorner(Position position);
|
|
void equalizeEdge(Position position);
|
|
|
|
void equalizeBoundaries();
|
|
|
|
void setTileComplete(bool complete);
|
|
bool getTileComplete() const { return _complete; }
|
|
|
|
void optimizeResolution();
|
|
|
|
osg::Node* createScene();
|
|
|
|
osg::StateSet* createStateSet();
|
|
osg::Node* createHeightField();
|
|
osg::Node* createPolygonal();
|
|
|
|
void unrefData();
|
|
|
|
|
|
DataSet* _dataSet;
|
|
std::string _name;
|
|
unsigned int _level;
|
|
unsigned int _tileX;
|
|
unsigned int _tileY;
|
|
GLenum _pixelFormat;
|
|
|
|
struct ImageData
|
|
{
|
|
ImageData():
|
|
_imagery_maxSourceResolutionX(0.0f),
|
|
_imagery_maxSourceResolutionY(0.0f) {}
|
|
|
|
|
|
float _imagery_maxSourceResolutionX;
|
|
float _imagery_maxSourceResolutionY;
|
|
|
|
osg::ref_ptr<DestinationData> _imagery;
|
|
};
|
|
|
|
std::vector<ImageData> _imagery;
|
|
|
|
inline ImageData& getImageData(unsigned int layer)
|
|
{
|
|
if (layer>=_imagery.size()) _imagery.resize(layer+1);
|
|
return _imagery[layer];
|
|
}
|
|
|
|
osg::ref_ptr<DestinationData> _terrain;
|
|
osg::ref_ptr<DestinationData> _models;
|
|
|
|
DestinationTile* _neighbour[NUMBER_OF_POSITIONS];
|
|
bool _equalized[NUMBER_OF_POSITIONS];
|
|
|
|
|
|
unsigned int _maxSourceLevel;
|
|
|
|
unsigned int _imagery_maxNumColumns;
|
|
unsigned int _imagery_maxNumRows;
|
|
|
|
unsigned int _terrain_maxNumColumns;
|
|
unsigned int _terrain_maxNumRows;
|
|
float _terrain_maxSourceResolutionX;
|
|
float _terrain_maxSourceResolutionY;
|
|
|
|
bool _complete;
|
|
|
|
typedef std::vector<osg::Vec2> HeightDeltaList;
|
|
HeightDeltaList _heightDeltas[NUMBER_OF_POSITIONS];
|
|
|
|
};
|
|
|
|
class OSGTERRAIN_EXPORT CompositeDestination : public osg::Referenced, public SpatialProperties
|
|
{
|
|
public:
|
|
|
|
CompositeDestination():
|
|
_dataSet(0),
|
|
_parent(0),
|
|
_level(0),
|
|
_tileX(0),
|
|
_tileY(0),
|
|
_type(GROUP),
|
|
_maxVisibleDistance(FLT_MAX),
|
|
_subTileGenerated(false) {}
|
|
|
|
CompositeDestination(osg::CoordinateSystemNode* cs, const GeospatialExtents& extents):
|
|
SpatialProperties(cs,extents),
|
|
_dataSet(0),
|
|
_parent(0),
|
|
_level(0),
|
|
_tileX(0),
|
|
_tileY(0),
|
|
_type(GROUP),
|
|
_maxVisibleDistance(FLT_MAX),
|
|
_subTileGenerated(false) {}
|
|
|
|
void computeNeighboursFromQuadMap();
|
|
|
|
void addRequiredResolutions(CompositeSource* sourceGraph);
|
|
|
|
void readFrom(CompositeSource* sourceGraph);
|
|
|
|
void equalizeBoundaries();
|
|
|
|
osg::Node* createScene();
|
|
|
|
bool areSubTilesComplete();
|
|
std::string getSubTileName();
|
|
osg::Node* createPagedLODScene();
|
|
osg::Node* createSubTileScene();
|
|
|
|
void unrefSubTileData();
|
|
void unrefLocalData();
|
|
|
|
void setSubTilesGenerated(bool generated) { _subTileGenerated=generated; }
|
|
bool getSubTilesGenerated() const { return _subTileGenerated; }
|
|
|
|
|
|
typedef std::vector< osg::ref_ptr<DestinationTile> > TileList;
|
|
typedef std::vector< osg::ref_ptr<CompositeDestination> > ChildList;
|
|
|
|
DataSet* _dataSet;
|
|
CompositeDestination* _parent;
|
|
std::string _name;
|
|
unsigned int _level;
|
|
unsigned int _tileX;
|
|
unsigned int _tileY;
|
|
CompositeType _type;
|
|
TileList _tiles;
|
|
ChildList _children;
|
|
float _maxVisibleDistance;
|
|
bool _subTileGenerated;
|
|
|
|
};
|
|
|
|
|
|
typedef std::map<unsigned int,CompositeDestination*> Row;
|
|
typedef std::map<unsigned int,Row> Level;
|
|
typedef std::map<unsigned int,Level> QuadMap;
|
|
|
|
void insertTileToQuadMap(CompositeDestination* tile)
|
|
{
|
|
_quadMap[tile->_level][tile->_tileY][tile->_tileX] = tile;
|
|
}
|
|
|
|
DestinationTile* getTile(unsigned int level,unsigned int X, unsigned int Y)
|
|
{
|
|
CompositeDestination* cd = getComposite(level,X,Y);
|
|
if (!cd) return 0;
|
|
if (cd->_tiles.empty()) return 0;
|
|
return (cd->_tiles).front().get();
|
|
}
|
|
|
|
CompositeDestination* getComposite(unsigned int level,unsigned int X, unsigned int Y)
|
|
{
|
|
QuadMap::iterator levelItr = _quadMap.find(level);
|
|
if (levelItr==_quadMap.end()) return 0;
|
|
|
|
Level::iterator rowItr = levelItr->second.find(Y);
|
|
if (rowItr==levelItr->second.end()) return 0;
|
|
|
|
Row::iterator columnItr = rowItr->second.find(X);
|
|
if (columnItr==rowItr->second.end()) return 0;
|
|
else return columnItr->second;
|
|
}
|
|
|
|
Row& getRow(unsigned int level,unsigned int Y)
|
|
{
|
|
return _quadMap[level][Y];
|
|
}
|
|
|
|
public:
|
|
|
|
|
|
DataSet();
|
|
|
|
|
|
void addSource(Source* source);
|
|
void addSource(CompositeSource* composite);
|
|
|
|
void loadSources();
|
|
|
|
void setMaximumTileImageSize(unsigned int size) { _maximumTileImageSize = size; }
|
|
unsigned int getMaximumTileImageSize() const { return _maximumTileImageSize; }
|
|
|
|
void setMaximumTileTerrainSize(unsigned int size) { _maximumTileTerrainSize = size; }
|
|
unsigned int getMaximumTileTerrainSize() const { return _maximumTileTerrainSize; }
|
|
|
|
void setMaximumVisibleDistanceOfTopLevel(float d) { _maximumVisiableDistanceOfTopLevel = d; }
|
|
float getMaximumVisibleDistanceOfTopLevel() const { return _maximumVisiableDistanceOfTopLevel; }
|
|
|
|
void setRadiusToMaxVisibleDistanceRatio(float ratio) { _radiusToMaxVisibleDistanceRatio = ratio; }
|
|
float getRadiusToMaxVisibleDistanceRatio() const { return _radiusToMaxVisibleDistanceRatio; }
|
|
|
|
void setVerticalScale(float verticalScale) { _verticalScale = verticalScale; }
|
|
float getVerticalScale() const { return _verticalScale; }
|
|
|
|
void setSkirtRatio(float skirtRatio) { _skirtRatio = skirtRatio; }
|
|
float getSkirtRatio() const { return _skirtRatio; }
|
|
|
|
void setDefaultColor(const osg::Vec4& defaultColor) { _defaultColor = defaultColor; }
|
|
const osg::Vec4& getDefaultColor() const { return _defaultColor; }
|
|
|
|
void setDestinationCoordinateSystem(const std::string& wellKnownText) { setDestinationCoordinateSystem(new osg::CoordinateSystemNode("WKT",wellKnownText)); }
|
|
void setDestinationCoordinateSystem(osg::CoordinateSystemNode* cs) { _destinationCoordinateSystem = cs; }
|
|
osg::CoordinateSystemNode* getDestinationCoordinateSystem() { return _destinationCoordinateSystem .get(); }
|
|
|
|
void setIntermediateCoordinateSystem(const std::string& wellKnownText) { setIntermediateCoordinateSystem(new osg::CoordinateSystemNode("WKT",wellKnownText)); }
|
|
void setIntermediateCoordinateSystem(osg::CoordinateSystemNode* cs) { _intermediateCoordinateSystem = cs; }
|
|
osg::CoordinateSystemNode* getIntermediateCoordinateSystem() { return _intermediateCoordinateSystem.get(); }
|
|
|
|
void setConvertFromGeographicToGeocentric(bool flag) { _convertFromGeographicToGeocentric = flag; }
|
|
bool getConvertFromGeographicToGeocentric() const { return _convertFromGeographicToGeocentric; }
|
|
|
|
void setEllipsoidModel(osg::EllipsoidModel* et) { _ellipsoidModel = et; }
|
|
osg::EllipsoidModel* getEllipsoidModel() { return _ellipsoidModel.get(); }
|
|
const osg::EllipsoidModel* getEllipsoidModel() const { return _ellipsoidModel.get(); }
|
|
|
|
bool mapLatLongsToXYZ() const { return getConvertFromGeographicToGeocentric() && getEllipsoidModel(); }
|
|
|
|
void setDestinationExtents(const GeospatialExtents& extents) { _extents = extents; }
|
|
|
|
void setDestinationGeoTransform(const osg::Matrixd& geoTransform) { _geoTransform = geoTransform; }
|
|
|
|
/** Set the Archive name if one is to be used.*/
|
|
void setArchiveName(const std::string& filename) { _archiveName = filename; }
|
|
|
|
/** Get the Archive name.*/
|
|
const std::string& getArchiveName() const { return _archiveName; }
|
|
|
|
/** Set the Archive.*/
|
|
void setArchive(osgDB::Archive* archive) { _archive = archive; }
|
|
|
|
/** Get the Archive if one is to being used.*/
|
|
osgDB::Archive* getArchive() { return _archive.get(); }
|
|
|
|
/** Set the Directory, DestinationTileBaseName and DestinationTileExtension from the passed in filename.*/
|
|
void setDestinationName(const std::string& filename);
|
|
|
|
void setDirectory(const std::string& directory);
|
|
const std::string& getDirectory() const { return _directory; }
|
|
|
|
void setDestinationTileBaseName(const std::string& basename) { _tileBasename = basename; }
|
|
const std::string& getDestinationTileBaseName() const { return _tileBasename; }
|
|
|
|
void setDestinationTileExtension(const std::string& extension) { _tileExtension = extension; }
|
|
const std::string& getDestinationTileExtension() const { return _tileExtension; }
|
|
|
|
void setDestinationImageExtension(const std::string& extension) { _imageExtension = extension; }
|
|
const std::string& getDestinationImageExtension() const { return _imageExtension; }
|
|
|
|
enum DatabaseType
|
|
{
|
|
LOD_DATABASE,
|
|
PagedLOD_DATABASE,
|
|
};
|
|
|
|
void setDatabaseType(DatabaseType type) { _databaseType = type; }
|
|
DatabaseType getDatabaseType() const { return _databaseType; }
|
|
|
|
enum GeometryType
|
|
{
|
|
HEIGHT_FIELD,
|
|
POLYGONAL,
|
|
};
|
|
void setGeometryType(GeometryType type) { _geometryType = type; }
|
|
GeometryType getGeometryType() const { return _geometryType; }
|
|
|
|
enum TextureType
|
|
{
|
|
RGB_24,
|
|
RGBA,
|
|
RGB_16,
|
|
RGBA_16,
|
|
COMPRESSED_TEXTURE,
|
|
COMPRESSED_RGBA_TEXTURE
|
|
};
|
|
void setTextureType(TextureType type) { _textureType = type; }
|
|
TextureType getTextureType() const { return _textureType; }
|
|
|
|
void setMaxAnisotropy(float d) { _maxAnisotropy = d; }
|
|
float getMaxAnisotropy() const { return _maxAnisotropy; }
|
|
|
|
|
|
enum MipMappingMode
|
|
{
|
|
NO_MIP_MAPPING, /// disable mip mapping - use LINEAR, LINEAR filters.
|
|
MIP_MAPPING_HARDWARE, /// use mip mapping, dynamically compute them in hardware if supported
|
|
MIP_MAPPING_IMAGERY /// use mip mapping, and store imagery along with associated mip maps.
|
|
};
|
|
|
|
void setMipMappingMode(MipMappingMode mipMappingMode) { _mipMappingMode = mipMappingMode; }
|
|
MipMappingMode getMipMappingMode() const { return _mipMappingMode; }
|
|
|
|
|
|
void setUseLocalTileTransform(bool flag) { _useLocalTileTransform = flag; }
|
|
bool getUseLocalTileTransform() const { return _useLocalTileTransform; }
|
|
|
|
void setSimplifyTerrain(bool flag) { _simplifyTerrain = flag; }
|
|
bool getSimplifyTerrain() const { return _simplifyTerrain; }
|
|
|
|
|
|
void setDecorateGeneratedSceneGraphWithCoordinateSystemNode(bool flag) { _decorateWithCoordinateSystemNode = flag; }
|
|
bool getDecorateGeneratedSceneGraphWithCoordinateSystemNode() const { return _decorateWithCoordinateSystemNode; }
|
|
|
|
|
|
void setDecorateGeneratedSceneGraphWithMultiTextureControl(bool flag) { _decorateWithMultiTextureControl = flag; }
|
|
bool getDecorateGeneratedSceneGraphWithMultiTextureControl() const { return _decorateWithMultiTextureControl; }
|
|
|
|
unsigned int getNumOfTextureLevels() const { return _numTextureLevels; }
|
|
|
|
void setCommentString(const std::string& comment) { _comment = comment; }
|
|
const std::string& getCommentString() const { return _comment; }
|
|
|
|
|
|
void setWriteNodeBeforeSimplification(bool flag) { _writeNodeBeforeSimplification = flag; }
|
|
bool getWriteNodeBeforeSimplification() const { return _writeNodeBeforeSimplification; }
|
|
|
|
|
|
static void setNotifyOffset(int level);
|
|
static int getNotifyOffset();
|
|
|
|
|
|
CompositeDestination* createDestinationGraph(CompositeDestination* parent,
|
|
osg::CoordinateSystemNode* cs,
|
|
const GeospatialExtents& extents,
|
|
unsigned int maxImageSize,
|
|
unsigned int maxTerrainSize,
|
|
unsigned int currentLevel,
|
|
unsigned int currentX,
|
|
unsigned int currentY,
|
|
unsigned int maxNumLevels);
|
|
|
|
|
|
void computeDestinationGraphFromSources(unsigned int numLevels);
|
|
void updateSourcesForDestinationGraphNeeds();
|
|
void populateDestinationGraphFromSources();
|
|
|
|
void createDestination(unsigned int numLevels);
|
|
|
|
void buildDestination() { _buildDestination(false); }
|
|
|
|
void writeDestination() { _buildDestination(true); }
|
|
|
|
osg::Node* getDestinationRootNode() { return _rootNode.get(); }
|
|
|
|
// helper functions for handling optional archive
|
|
void _writeNodeFile(const osg::Node& node,const std::string& filename);
|
|
void _writeImageFile(const osg::Image& image,const std::string& filename);
|
|
|
|
void setState(osg::State* state) { _state = state; }
|
|
osg::State* getState() { return _state.get(); }
|
|
|
|
protected:
|
|
|
|
virtual ~DataSet() {}
|
|
|
|
|
|
|
|
void _readRow(Row& row);
|
|
void _equalizeRow(Row& row);
|
|
void _writeRow(Row& row);
|
|
void _buildDestination(bool writeToDisk);
|
|
|
|
void init();
|
|
|
|
osg::Node* decorateWithCoordinateSystemNode(osg::Node* subgraph);
|
|
osg::Node* decorateWithMultiTextureControl(osg::Node* subgraph);
|
|
|
|
|
|
osg::ref_ptr<CompositeSource> _sourceGraph;
|
|
|
|
osg::ref_ptr<CompositeDestination> _destinationGraph;
|
|
|
|
QuadMap _quadMap;
|
|
|
|
|
|
|
|
unsigned int _maximumTileImageSize;
|
|
unsigned int _maximumTileTerrainSize;
|
|
float _maximumVisiableDistanceOfTopLevel;
|
|
float _radiusToMaxVisibleDistanceRatio;
|
|
float _verticalScale;
|
|
float _skirtRatio;
|
|
|
|
osg::ref_ptr<osg::CoordinateSystemNode> _destinationCoordinateSystem;
|
|
osg::ref_ptr<osg::CoordinateSystemNode> _intermediateCoordinateSystem;
|
|
|
|
bool _convertFromGeographicToGeocentric;
|
|
osg::ref_ptr<osg::EllipsoidModel> _ellipsoidModel;
|
|
|
|
osg::Matrixd _geoTransform;
|
|
GeospatialExtents _extents;
|
|
std::string _archiveName;
|
|
osg::ref_ptr<osgDB::Archive> _archive;
|
|
std::string _directory;
|
|
std::string _tileBasename;
|
|
std::string _tileExtension;
|
|
std::string _imageExtension;
|
|
osg::Vec4 _defaultColor;
|
|
DatabaseType _databaseType;
|
|
GeometryType _geometryType;
|
|
TextureType _textureType;
|
|
float _maxAnisotropy;
|
|
MipMappingMode _mipMappingMode;
|
|
|
|
unsigned int _numTextureLevels;
|
|
|
|
bool _useLocalTileTransform;
|
|
|
|
bool _decorateWithCoordinateSystemNode;
|
|
bool _decorateWithMultiTextureControl;
|
|
|
|
std::string _comment;
|
|
|
|
bool _writeNodeBeforeSimplification;
|
|
|
|
bool _simplifyTerrain;
|
|
|
|
osg::ref_ptr<osg::Node> _rootNode;
|
|
osg::ref_ptr<osg::State> _state;
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|