|
osgEarth 2.1.1
|
Static Public Member Functions | |
| static float | getHeightAtPixel (const osg::HeightField *hf, double c, double r, ElevationInterpolation interpoltion=INTERP_BILINEAR) |
| static float | getHeightAtLocation (const osg::HeightField *hf, double x, double y, double llx, double lly, double dx, double dy, ElevationInterpolation interpolation=INTERP_BILINEAR) |
| static float | getHeightAtNormalizedLocation (const osg::HeightField *hf, double nx, double ny, ElevationInterpolation interp=INTERP_BILINEAR) |
| static void | scaleHeightFieldToDegrees (osg::HeightField *hf) |
| static osg::HeightField * | createSubSample (osg::HeightField *input, const class GeoExtent &inputEx, const class GeoExtent &outputEx, ElevationInterpolation interpolation=INTERP_BILINEAR) |
| static osg::HeightField * | resizeHeightField (osg::HeightField *input, int newX, int newY, ElevationInterpolation interp=INTERP_BILINEAR) |
| static osg::ClusterCullingCallback * | createClusterCullingCallback (osg::HeightField *grid, osg::EllipsoidModel *em, float verticalScale=1.0f) |
Definition at line 54 of file HeightFieldUtils.
| osg::ClusterCullingCallback * HeightFieldUtils::createClusterCullingCallback | ( | osg::HeightField * | grid, |
| osg::EllipsoidModel * | em, | ||
| float | verticalScale = 1.0f |
||
| ) | [static] |
Creates a new cluster culler based on a heightfield. Cluster cullers are for geocentric maps only, and therefore requires the ellipsoid model.
Definition at line 308 of file HeightFieldUtils.cpp.
{
//This code is a very slightly modified version of the DestinationTile::createClusterCullingCallback in VirtualPlanetBuilder.
if ( !grid || !et )
return 0L;
double globe_radius = et->getRadiusPolar();
unsigned int numColumns = grid->getNumColumns();
unsigned int numRows = grid->getNumRows();
double midLong = grid->getOrigin().x()+grid->getXInterval()*((double)(numColumns-1))*0.5;
double midLat = grid->getOrigin().y()+grid->getYInterval()*((double)(numRows-1))*0.5;
double midZ = grid->getOrigin().z();
double midX,midY;
et->convertLatLongHeightToXYZ(osg::DegreesToRadians(midLat),osg::DegreesToRadians(midLong),midZ, midX,midY,midZ);
osg::Vec3 center_position(midX,midY,midZ);
osg::Vec3 center_normal(midX,midY,midZ);
center_normal.normalize();
osg::Vec3 transformed_center_normal = center_normal;
unsigned int r,c;
// populate the vertex/normal/texcoord arrays from the grid.
double orig_X = grid->getOrigin().x();
double delta_X = grid->getXInterval();
double orig_Y = grid->getOrigin().y();
double delta_Y = grid->getYInterval();
double orig_Z = grid->getOrigin().z();
float min_dot_product = 1.0f;
float max_cluster_culling_height = 0.0f;
float max_cluster_culling_radius = 0.0f;
for(r=0;r<numRows;++r)
{
for(c=0;c<numColumns;++c)
{
double X = orig_X + delta_X*(double)c;
double Y = orig_Y + delta_Y*(double)r;
double Z = orig_Z + grid->getHeight(c,r) * verticalScale;
double height = Z;
et->convertLatLongHeightToXYZ(
osg::DegreesToRadians(Y), osg::DegreesToRadians(X), Z,
X, Y, Z);
osg::Vec3d v(X,Y,Z);
osg::Vec3 dv = v - center_position;
double d = sqrt(dv.x()*dv.x() + dv.y()*dv.y() + dv.z()*dv.z());
double theta = acos( globe_radius/ (globe_radius + fabs(height)) );
double phi = 2.0 * asin (d*0.5/globe_radius); // d/globe_radius;
double beta = theta+phi;
double cutoff = osg::PI_2 - 0.1;
//log(osg::INFO,"theta="<<theta<<"\tphi="<<phi<<" beta "<<beta);
if (phi<cutoff && beta<cutoff)
{
float local_dot_product = -sin(theta + phi);
float local_m = globe_radius*( 1.0/ cos(theta+phi) - 1.0);
float local_radius = static_cast<float>(globe_radius * tan(beta)); // beta*globe_radius;
min_dot_product = osg::minimum(min_dot_product, local_dot_product);
max_cluster_culling_height = osg::maximum(max_cluster_culling_height,local_m);
max_cluster_culling_radius = osg::maximum(max_cluster_culling_radius,local_radius);
}
else
{
//log(osg::INFO,"Turning off cluster culling for wrap around tile.");
return 0;
}
}
}
osg::ClusterCullingCallback* ccc = new osg::ClusterCullingCallback;
ccc->set(center_position + transformed_center_normal*max_cluster_culling_height ,
transformed_center_normal,
min_dot_product,
max_cluster_culling_radius);
return ccc;
}
| osg::HeightField * HeightFieldUtils::createSubSample | ( | osg::HeightField * | input, |
| const class GeoExtent & | inputEx, | ||
| const class GeoExtent & | outputEx, | ||
| ElevationInterpolation | interpolation = INTERP_BILINEAR |
||
| ) | [static] |
Subsamples a heightfield to the specified extent.
Definition at line 225 of file HeightFieldUtils.cpp.
{
double div = outputEx.width()/inputEx.width();
if ( div >= 1.0f )
return 0L;
int numCols = input->getNumColumns();
int numRows = input->getNumRows();
//float dx = input->getXInterval() * div;
//float dy = input->getYInterval() * div;
double xInterval = inputEx.width() / (double)(input->getNumColumns()-1);
double yInterval = inputEx.height() / (double)(input->getNumRows()-1);
double dx = div * xInterval;
double dy = div * yInterval;
osg::HeightField* dest = new osg::HeightField();
dest->allocate( numCols, numRows );
dest->setXInterval( dx );
dest->setYInterval( dy );
// copy over the skirt height, adjusting it for relative tile size.
dest->setSkirtHeight( input->getSkirtHeight() * div );
double x, y;
int col, row;
for( x = outputEx.xMin(), col=0; col < numCols; x += dx, col++ )
{
for( y = outputEx.yMin(), row=0; row < numRows; y += dy, row++ )
{
float height = HeightFieldUtils::getHeightAtLocation( input, x, y, inputEx.xMin(), inputEx.yMin(), xInterval, yInterval, interpolation);
dest->setHeight( col, row, height );
}
}
osg::Vec3d orig( outputEx.xMin(), outputEx.yMin(), input->getOrigin().z() );
dest->setOrigin( orig );
return dest;
}
Here is the call graph for this function:| float HeightFieldUtils::getHeightAtLocation | ( | const osg::HeightField * | hf, |
| double | x, | ||
| double | y, | ||
| double | llx, | ||
| double | lly, | ||
| double | dx, | ||
| double | dy, | ||
| ElevationInterpolation | interpolation = INTERP_BILINEAR |
||
| ) | [static] |
Gets the interpolated height value at the specific geolocation.
Definition at line 184 of file HeightFieldUtils.cpp.
{
//Determine the pixel to sample
double px = osg::clampBetween( (x - llx) / dx, 0.0, (double)(hf->getNumColumns()-1) );
double py = osg::clampBetween( (y - lly) / dy, 0.0, (double)(hf->getNumRows()-1) );
return getHeightAtPixel(hf, px, py, interpolation);
}
Here is the call graph for this function:
Here is the caller graph for this function:| float HeightFieldUtils::getHeightAtNormalizedLocation | ( | const osg::HeightField * | hf, |
| double | nx, | ||
| double | ny, | ||
| ElevationInterpolation | interp = INTERP_BILINEAR |
||
| ) | [static] |
Gets the interpolated elevation at the specified "normalized unit location". i.e., nx => [0.0, 1.0], ny => [0.0, 1.0] where 0.0 and 1.0 are the opposing endposts of the heightfield.
Definition at line 193 of file HeightFieldUtils.cpp.
{
double px = nx * (double)(input->getNumColumns() - 1);
double py = ny * (double)(input->getNumRows() - 1);
return getHeightAtPixel( input, px, py, interp );
}
Here is the call graph for this function:
Here is the caller graph for this function:| float HeightFieldUtils::getHeightAtPixel | ( | const osg::HeightField * | hf, |
| double | c, | ||
| double | r, | ||
| ElevationInterpolation | interpoltion = INTERP_BILINEAR |
||
| ) | [static] |
Gets the interpolated height value at the specified fractional pixel position.
Definition at line 27 of file HeightFieldUtils.cpp.
{
float result = 0.0;
if (interpolation == INTERP_NEAREST)
{
//Nearest interpolation
result = hf->getHeight((unsigned int)osg::round(c), (unsigned int)osg::round(r));
}
else if (interpolation == INTERP_TRIANGULATE)
{
//Interpolation to make sure that the interpolated point follows the triangles generated by the 4 parent points
int rowMin = osg::maximum((int)floor(r), 0);
int rowMax = osg::maximum(osg::minimum((int)ceil(r), (int)(hf->getNumRows()-1)), 0);
int colMin = osg::maximum((int)floor(c), 0);
int colMax = osg::maximum(osg::minimum((int)ceil(c), (int)(hf->getNumColumns()-1)), 0);
if (rowMin == rowMax)
{
if (rowMin < (int)hf->getNumRows()-2)
{
rowMax = rowMin + 1;
}
else
{
rowMin = rowMax - 1;
}
}
if (colMin == colMax)
{
if (colMin < (int)hf->getNumColumns()-2)
{
colMax = colMin + 1;
}
else
{
colMin = colMax - 1;
}
}
if (rowMin > rowMax) rowMin = rowMax;
if (colMin > colMax) colMin = colMax;
float urHeight = hf->getHeight(colMax, rowMax);
float llHeight = hf->getHeight(colMin, rowMin);
float ulHeight = hf->getHeight(colMin, rowMax);
float lrHeight = hf->getHeight(colMax, rowMin);
//Make sure not to use NoData in the interpolation
if (urHeight == NO_DATA_VALUE || llHeight == NO_DATA_VALUE || ulHeight == NO_DATA_VALUE || lrHeight == NO_DATA_VALUE)
{
return NO_DATA_VALUE;
}
double dx = c - (double)colMin;
double dy = r - (double)rowMin;
//The quad consisting of the 4 corner points can be made into two triangles.
//The "left" triangle is ll, ur, ul
//The "right" triangle is ll, lr, ur
//Determine which triangle the point falls in.
osg::Vec3d v0, v1, v2;
if (dx > dy)
{
//The point lies in the right triangle
v0.set(colMin, rowMin, llHeight);
v1.set(colMax, rowMin, lrHeight);
v2.set(colMax, rowMax, urHeight);
}
else
{
//The point lies in the left triangle
v0.set(colMin, rowMin, llHeight);
v1.set(colMax, rowMax, urHeight);
v2.set(colMin, rowMax, ulHeight);
}
//Compute the normal
osg::Vec3d n = (v1 - v0) ^ (v2 - v0);
result = ( n.x() * ( c - v0.x() ) + n.y() * ( r - v0.y() ) ) / -n.z() + v0.z();
}
else
{
//OE_INFO << "getHeightAtPixel: (" << c << ", " << r << ")" << std::endl;
int rowMin = osg::maximum((int)floor(r), 0);
int rowMax = osg::maximum(osg::minimum((int)ceil(r), (int)(hf->getNumRows()-1)), 0);
int colMin = osg::maximum((int)floor(c), 0);
int colMax = osg::maximum(osg::minimum((int)ceil(c), (int)(hf->getNumColumns()-1)), 0);
if (rowMin > rowMax) rowMin = rowMax;
if (colMin > colMax) colMin = colMax;
float urHeight = hf->getHeight(colMax, rowMax);
float llHeight = hf->getHeight(colMin, rowMin);
float ulHeight = hf->getHeight(colMin, rowMax);
float lrHeight = hf->getHeight(colMax, rowMin);
//Make sure not to use NoData in the interpolation
if (urHeight == NO_DATA_VALUE || llHeight == NO_DATA_VALUE || ulHeight == NO_DATA_VALUE || lrHeight == NO_DATA_VALUE)
{
return NO_DATA_VALUE;
}
//OE_INFO << "Heights (ll, lr, ul, ur) ( " << llHeight << ", " << urHeight << ", " << ulHeight << ", " << urHeight << std::endl;
if (interpolation == INTERP_BILINEAR)
{
//Check for exact value
if ((colMax == colMin) && (rowMax == rowMin))
{
//OE_NOTICE << "Exact value" << std::endl;
result = hf->getHeight((int)c, (int)r);
}
else if (colMax == colMin)
{
//OE_NOTICE << "Vertically" << std::endl;
//Linear interpolate vertically
result = ((double)rowMax - r) * llHeight + (r - (double)rowMin) * ulHeight;
}
else if (rowMax == rowMin)
{
//OE_NOTICE << "Horizontally" << std::endl;
//Linear interpolate horizontally
result = ((double)colMax - c) * llHeight + (c - (double)colMin) * lrHeight;
}
else
{
//OE_NOTICE << "Bilinear" << std::endl;
//Bilinear interpolate
float r1 = ((double)colMax - c) * llHeight + (c - (double)colMin) * lrHeight;
float r2 = ((double)colMax - c) * ulHeight + (c - (double)colMin) * urHeight;
//OE_INFO << "r1, r2 = " << r1 << " , " << r2 << std::endl;
result = ((double)rowMax - r) * r1 + (r - (double)rowMin) * r2;
}
}
else if (interpolation == INTERP_AVERAGE)
{
double x_rem = c - (int)c;
double y_rem = r - (int)r;
double w00 = (1.0 - y_rem) * (1.0 - x_rem) * (double)llHeight;
double w01 = (1.0 - y_rem) * x_rem * (double)lrHeight;
double w10 = y_rem * (1.0 - x_rem) * (double)ulHeight;
double w11 = y_rem * x_rem * (double)urHeight;
result = (float)(w00 + w01 + w10 + w11);
}
}
return result;
}
Here is the caller graph for this function:| osg::HeightField * HeightFieldUtils::resizeHeightField | ( | osg::HeightField * | input, |
| int | newX, | ||
| int | newY, | ||
| ElevationInterpolation | interp = INTERP_BILINEAR |
||
| ) | [static] |
Resizes a heightfield, keeping the corner values the same and resampling the internal posts.
Definition at line 271 of file HeightFieldUtils.cpp.
{
if ( newColumns <= 1 && newRows <= 1 )
return 0L;
if ( newColumns == input->getNumColumns() && newRows == (int)input->getNumRows() )
return new osg::HeightField( *input, osg::CopyOp::DEEP_COPY_ALL );
double spanX = (input->getNumColumns()-1) * input->getXInterval();
double spanY = (input->getNumRows()-1) * input->getYInterval();
const osg::Vec3& origin = input->getOrigin();
double stepX = spanX/(double)(newColumns-1);
double stepY = spanY/(double)(newRows-1);
osg::HeightField* output = new osg::HeightField();
output->allocate( newColumns, newRows );
output->setXInterval( stepX );
output->setYInterval( stepY );
output->setOrigin( origin );
for( int y = 0; y < newRows; ++y )
{
for( int x = 0; x < newColumns; ++x )
{
double nx = (double)x / (double)(newColumns-1);
double ny = (double)y / (double)(newRows-1);
float h = getHeightAtNormalizedLocation( input, nx, ny );
output->setHeight( x, y, h );
}
}
return output;
}
Here is the call graph for this function:| void HeightFieldUtils::scaleHeightFieldToDegrees | ( | osg::HeightField * | hf | ) | [static] |
Scales all the height values in a heightfield from scalar units to "linear degrees". The only purpose of this is to show reasonable height values in a projected Plate Carre map (in which vertical units are not well defined).
Definition at line 204 of file HeightFieldUtils.cpp.
{
if (hf)
{
//The number of degrees in a meter at the equator
//TODO: adjust this calculation based on the actual EllipsoidModel.
float scale = 1.0f/111319.0f;
for (unsigned int i = 0; i < hf->getHeightList().size(); ++i)
{
hf->getHeightList()[i] *= scale;
}
}
else
{
OE_WARN << "[osgEarth::HeightFieldUtils] scaleHeightFieldToDegrees heightfield is NULL" << std::endl;
}
}
Here is the caller graph for this function:
1.7.3