{
unsigned int lowestLOD = key.getLevelOfDetail();
bool hfInitialized = false;
typedef std::map< TerrainLayer*, bool > LayerValidMap;
LayerValidMap layerValidMap;
GeoHeightFieldVector heightFields;
unsigned int numValidHeightFields = 0;
if ( out_isFallback )
{
*out_isFallback = false;
}
for( ElevationLayerVector::const_iterator i = elevLayers.begin(); i != elevLayers.end(); i++ )
{
ElevationLayer* layer = i->get();
if (layer->getProfile() && layer->getEnabled() )
{
osg::HeightField* hf = layer->createHeightField( key, progress );
layerValidMap[ layer ] = (hf != 0L);
if ( hf ) {
numValidHeightFields++;
GeoHeightField ghf( hf, key.getExtent(), layer->getProfile()->getVerticalSRS() );
heightFields.push_back( ghf );
}
}
}
if (numValidHeightFields == 0 && !fallback)
{
return false;
}
for( ElevationLayerVector::const_iterator i = elevLayers.begin(); i != elevLayers.end(); i++ )
{
ElevationLayer* layer = i->get();
if (layer->getProfile() && layer->getEnabled() )
{
if (!layerValidMap[ layer ])
{
TileKey hf_key = key;
osg::ref_ptr< osg::HeightField > hf;
while (hf_key.valid())
{
hf = layer->createHeightField( hf_key, progress );
if ( hf.valid() )
break;
hf_key = hf_key.createParentKey();
}
if (hf.valid())
{
if ( hf_key.getLevelOfDetail() < lowestLOD )
lowestLOD = hf_key.getLevelOfDetail();
heightFields.push_back( GeoHeightField(
hf.get(), hf_key.getExtent(), layer->getProfile()->getVerticalSRS() ) );
if ( out_isFallback )
*out_isFallback = true;
}
}
}
}
if (heightFields.size() == 0)
{
return false;
}
else if (heightFields.size() == 1)
{
if ( lowestLOD == key.getLevelOfDetail() )
{
out_result = heightFields[0].takeHeightField();
}
else
{
GeoHeightField geoHF = heightFields[0].createSubSample( key.getExtent(), interpolation);
out_result = geoHF.takeHeightField();
hfInitialized = true;
}
}
else
{
unsigned int width = 0;
unsigned int height = 0;
for (GeoHeightFieldVector::const_iterator i = heightFields.begin(); i < heightFields.end(); ++i)
{
if (i->getHeightField()->getNumColumns() > width)
width = i->getHeightField()->getNumColumns();
if (i->getHeightField()->getNumRows() > height)
height = i->getHeightField()->getNumRows();
}
out_result = new osg::HeightField();
out_result->allocate( width, height );
double minx, miny, maxx, maxy;
key.getExtent().getBounds(minx, miny, maxx, maxy);
double dx = (maxx - minx)/(double)(out_result->getNumColumns()-1);
double dy = (maxy - miny)/(double)(out_result->getNumRows()-1);
const VerticalSpatialReference* vsrs = mapProfile->getVerticalSRS();
for (unsigned int c = 0; c < width; ++c)
{
double geoX = minx + (dx * (double)c);
for (unsigned r = 0; r < height; ++r)
{
double geoY = miny + (dy * (double)r);
std::vector<float> elevations;
for (GeoHeightFieldVector::iterator itr = heightFields.begin(); itr != heightFields.end(); ++itr)
{
const GeoHeightField& geoHF = *itr;
float elevation = 0.0f;
if ( geoHF.getElevation(key.getExtent().getSRS(), geoX, geoY, interpolation, vsrs, elevation) )
{
if (elevation != NO_DATA_VALUE)
{
elevations.push_back(elevation);
}
}
}
float elevation = NO_DATA_VALUE;
if (elevations.size() > 0)
{
if (samplePolicy == SAMPLE_FIRST_VALID)
{
elevation = elevations[0];
}
else if (samplePolicy == SAMPLE_HIGHEST)
{
elevation = -FLT_MAX;
for (unsigned int i = 0; i < elevations.size(); ++i)
{
if (elevation < elevations[i]) elevation = elevations[i];
}
}
else if (samplePolicy == SAMPLE_LOWEST)
{
elevation = FLT_MAX;
for (unsigned i = 0; i < elevations.size(); ++i)
{
if (elevation > elevations[i]) elevation = elevations[i];
}
}
else if (samplePolicy == SAMPLE_AVERAGE)
{
elevation = 0.0;
for (unsigned i = 0; i < elevations.size(); ++i)
{
elevation += elevations[i];
}
elevation /= (float)elevations.size();
}
}
out_result->setHeight(c, r, elevation);
}
}
}
if (out_result.valid())
{
ReplaceInvalidDataOperator o;
o.setValidDataOperator(new osgTerrain::NoDataValue(NO_DATA_VALUE));
o( out_result.get() );
}
if (out_result.valid() && !hfInitialized )
{
double minx, miny, maxx, maxy;
key.getExtent().getBounds(minx, miny, maxx, maxy);
out_result->setOrigin( osg::Vec3d( minx, miny, 0.0 ) );
double dx = (maxx - minx)/(double)(out_result->getNumColumns()-1);
double dy = (maxy - miny)/(double)(out_result->getNumRows()-1);
out_result->setXInterval( dx );
out_result->setYInterval( dy );
out_result->setBorderWidth( 0 );
}
return out_result.valid();
}