osgEarth 2.1.1
|
Public Member Functions | |
ScatterFilter () | |
void | setDensity (float value) |
float | getDensity () const |
void | setRandom (bool value) |
bool | getRandom () const |
void | setRandomSeed (unsigned value) |
unsigned | getRandomSeed () const |
virtual FilterContext | push (FeatureList &input, FilterContext &context) |
Static Public Member Functions | |
static bool | isSupported () |
Protected Member Functions | |
void | polyScatter (const Geometry *input, const SpatialReference *inputSRS, const FilterContext &context, PointSet *output) |
void | lineScatter (const Geometry *input, const SpatialReference *inputSRS, const FilterContext &context, PointSet *output) |
Private Attributes | |
float | _density |
bool | _random |
unsigned | _randomSeed |
Random | _prng |
Feature filter that will take source feature and scatter points within that feature. It will either scatter points randomly (the default), or at fixed intervals, based on the density.
Definition at line 37 of file ScatterFilter.
ScatterFilter::ScatterFilter | ( | ) |
Definition at line 34 of file ScatterFilter.cpp.
: _density ( 10.0f ), _random ( true ), _randomSeed( 1 ) { //NOP }
float osgEarth::Features::ScatterFilter::getDensity | ( | ) | const [inline] |
Definition at line 48 of file ScatterFilter.
{ return _density; }
bool osgEarth::Features::ScatterFilter::getRandom | ( | ) | const [inline] |
Definition at line 52 of file ScatterFilter.
{ return _random; }
unsigned osgEarth::Features::ScatterFilter::getRandomSeed | ( | ) | const [inline] |
Definition at line 56 of file ScatterFilter.
{ return _randomSeed; }
static bool osgEarth::Features::ScatterFilter::isSupported | ( | ) | [inline, static] |
Definition at line 41 of file ScatterFilter.
{ return true; }
void ScatterFilter::lineScatter | ( | const Geometry * | input, |
const SpatialReference * | inputSRS, | ||
const FilterContext & | context, | ||
PointSet * | output | ||
) | [protected] |
Definition at line 124 of file ScatterFilter.cpp.
{ // calculate the number of instances per linear km. float instPerKm = sqrt( osg::clampAbove( 0.1f, _density ) ); bool isGeo = inputSRS->isGeographic(); ConstGeometryIterator iter( input ); while( iter.hasMore() ) { const Geometry* part = iter.next(); // see whether it's a ring, because rings have to connect the last two points. bool isRing = part->getType() == Geometry::TYPE_RING; for( unsigned i=0; i<part->size(); ++i ) { // done if we're not traversing a ring. if ( !isRing && i+1 == part->size() ) break; // extract the segment: const osg::Vec3d& p0 = (*part)[i]; const osg::Vec3d& p1 = isRing && i+1 == part->size() ? (*part)[0] : (*part)[i+1]; // figure out the segment length in meters (assumed geodetic coords) double seglen_m; double seglen_native = (p1-p0).length(); if ( isGeo ) { seglen_m = GeoMath::distance( osg::DegreesToRadians( p0.y() ), osg::DegreesToRadians( p0.x() ), osg::DegreesToRadians( p1.y() ), osg::DegreesToRadians( p1.x() ) ); } else // projected { seglen_m = seglen_native; } unsigned numInstances = (seglen_m*0.001) * instPerKm; if ( numInstances > 0 ) { // a unit vector for scattering points along the segment osg::Vec3d unit = p1-p0; unit.normalize(); for( unsigned n=0; n<numInstances; ++n ) { double offset = _prng.next() * seglen_native; output->push_back( p0 + unit*offset ); } } } } }
void ScatterFilter::polyScatter | ( | const Geometry * | input, |
const SpatialReference * | inputSRS, | ||
const FilterContext & | context, | ||
PointSet * | output | ||
) | [protected] |
Definition at line 43 of file ScatterFilter.cpp.
{ Bounds bounds; double areaSqKm = 0.0; ConstGeometryIterator iter( input, false ); while( iter.hasMore() ) { const Polygon* polygon = dynamic_cast<const Polygon*>( iter.next() ); if ( !polygon ) continue; if ( /*context.isGeocentric() ||*/ context.profile()->getSRS()->isGeographic() ) { bounds = polygon->getBounds(); double avglat = bounds.yMin() + 0.5*bounds.height(); double h = bounds.height() * 111.32; double w = bounds.width() * 111.32 * sin( 1.57079633 + osg::DegreesToRadians(avglat) ); areaSqKm = w * h; } else if ( context.profile()->getSRS()->isProjected() ) { bounds = polygon->getBounds(); areaSqKm = (0.001*bounds.width()) * (0.001*bounds.height()); } double zMin = 0.0; unsigned numInstancesInBoundingRect = areaSqKm * (double)osg::clampAbove( 0.1f, _density ); if ( numInstancesInBoundingRect == 0 ) continue; if ( _random ) { // Random scattering. Note, we try to place as many instances as would // fit in the bounding rectangle; The real placed number will be less since // we only place models inside the actual polygon. But the density will // be correct. for( unsigned j=0; j<numInstancesInBoundingRect; ++j ) { double x = bounds.xMin() + _prng.next() * bounds.width(); double y = bounds.yMin() + _prng.next() * bounds.height(); bool include = true; if ( include && polygon->contains2D( x, y ) ) output->push_back( osg::Vec3d(x, y, zMin) ); } } else { // regular interval scattering: double numInst1D = sqrt((double)numInstancesInBoundingRect); double ar = bounds.width() / bounds.height(); unsigned cols = (unsigned)( numInst1D * ar ); unsigned rows = (unsigned)( numInst1D / ar ); double colInterval = bounds.width() / (double)(cols-1); double rowInterval = bounds.height() / (double)(rows-1); double interval = 0.5*(colInterval+rowInterval); for( double cy=bounds.yMin(); cy<=bounds.yMax(); cy += interval ) { for( double cx = bounds.xMin(); cx <= bounds.xMax(); cx += interval ) { bool include = true; if ( include && polygon->contains2D( cx, cy ) ) output->push_back( osg::Vec3d(cx, cy, zMin) ); } } } } }
FilterContext ScatterFilter::push | ( | FeatureList & | input, |
FilterContext & | context | ||
) | [virtual] |
Processes a new feature list
Implements osgEarth::Features::FeatureFilter.
Definition at line 185 of file ScatterFilter.cpp.
{ if ( !isSupported() ) { OE_WARN << LC << "support for this filter is not enabled" << std::endl; return context; } // seed the random number generator so the randomness is the same each time _prng = Random( _randomSeed, Random::METHOD_FAST ); for( FeatureList::iterator i = features.begin(); i != features.end(); ++i ) { Feature* f = i->get(); Geometry* geom = f->getGeometry(); if ( !geom ) continue; const SpatialReference* geomSRS = context.profile()->getSRS(); PointSet* points = new PointSet(); if ( geom->getComponentType() == Geometry::TYPE_POLYGON ) { polyScatter( geom, geomSRS, context, points ); } else if ( geom->getComponentType() == Geometry::TYPE_LINESTRING || geom->getComponentType() == Geometry::TYPE_RING ) { lineScatter( geom, geomSRS, context, points ); } else { OE_WARN << LC << "Sorry, don't know how to scatter a PointSet yet" << std::endl; } // replace the source geometry with the scattered points. f->setGeometry( points ); } return context; }
void osgEarth::Features::ScatterFilter::setDensity | ( | float | value | ) | [inline] |
Approximate instances per sqkm.
Definition at line 47 of file ScatterFilter.
{ _density = value; }
void osgEarth::Features::ScatterFilter::setRandom | ( | bool | value | ) | [inline] |
Whether to randomly scatter (as opposed to a fixed interval scatter)
Definition at line 51 of file ScatterFilter.
{ _random = value; }
void osgEarth::Features::ScatterFilter::setRandomSeed | ( | unsigned | value | ) | [inline] |
Seed value for the random number generator
Definition at line 55 of file ScatterFilter.
{ _randomSeed = value; }
float osgEarth::Features::ScatterFilter::_density [private] |
Definition at line 76 of file ScatterFilter.
Definition at line 79 of file ScatterFilter.
bool osgEarth::Features::ScatterFilter::_random [private] |
Definition at line 77 of file ScatterFilter.
unsigned osgEarth::Features::ScatterFilter::_randomSeed [private] |
Definition at line 78 of file ScatterFilter.