|
osgEarth 2.1.1
|
Public Member Functions | |
| BuildTextOperator (bool hideClutter=false) | |
| osg::Node * | operator() (const FeatureList &features, const osgEarth::Symbology::TextSymbol *symbol, const FilterContext &context) |
Protected Attributes | |
| bool | _hideClutter |
Creates a text node that labels feature data.
Definition at line 34 of file BuildTextOperator.
| osgEarth::Features::BuildTextOperator::BuildTextOperator | ( | bool | hideClutter = false | ) | [inline] |
Definition at line 37 of file BuildTextOperator.
: _hideClutter(hideClutter) { };
| osg::Node * BuildTextOperator::operator() | ( | const FeatureList & | features, |
| const osgEarth::Symbology::TextSymbol * | symbol, | ||
| const FilterContext & | context | ||
| ) |
Definition at line 81 of file BuildTextOperator.cpp.
{
if (!symbol) return 0;
std::set< std::string > labelNames;
bool removeDuplicateLabels = symbol->removeDuplicateLabels().isSet() ? symbol->removeDuplicateLabels().get() : false;
StringExpression contentExpr = *symbol->content();
osg::Geode* result = new osg::Geode;
for (FeatureList::const_iterator itr = features.begin(); itr != features.end(); ++itr)
{
Feature* feature = itr->get();
if (!feature->getGeometry()) continue;
std::string text;
if (symbol->content().isSet())
{
//Get the text from the specified content and referenced attributes
text = feature->eval( contentExpr );
}
if (text.empty()) continue;
//See if there is a duplicate name
if (removeDuplicateLabels && labelNames.find(text) != labelNames.end()) continue;
bool rotateToScreen = symbol->rotateToScreen().isSet() ? symbol->rotateToScreen().value() : false;
// find the centroid
osg::Vec3d position;
osg::Quat orientation;
GeometryIterator gi( feature->getGeometry() );
while( gi.hasMore() )
{
Geometry* geom = gi.next();
TextSymbol::LinePlacement linePlacement = symbol->linePlacement().isSet() ? symbol->linePlacement().get() : TextSymbol::LINEPLACEMENT_ALONG_LINE;
if (geom->getType() == Symbology::Geometry::TYPE_LINESTRING && linePlacement == TextSymbol::LINEPLACEMENT_ALONG_LINE)
{
//Compute the "middle" of the line string
LineString* lineString = static_cast<LineString*>(geom);
double length = lineString->getLength();
double center = length / 2.0;
osg::Vec3d start, end;
if (lineString->getSegment(center, start, end))
{
TextSymbol::LineOrientation lineOrientation = symbol->lineOrientation().isSet() ? symbol->lineOrientation().get() : TextSymbol::LINEORIENTATION_HORIZONTAL;
position = (end + start) / 2.0;
//We don't want to orient the text at all if we are rotating to the screen
if (!rotateToScreen && lineOrientation != TextSymbol::LINEORIENTATION_HORIZONTAL)
{
osg::Vec3d dir = (end-start);
dir.normalize();
if (lineOrientation == TextSymbol::LINEORIENTATION_PERPENDICULAR)
{
osg::Vec3d up(0,0,1);
const SpatialReference* srs = context.profile()->getSRS();
if (srs && context.isGeocentric() && srs->getEllipsoid())
{
osg::Vec3d w = context.toWorld( position );
up = srs->getEllipsoid()->computeLocalUpVector(w.x(), w.y(), w.z());
}
dir = up ^ dir;
}
orientation.makeRotate(osg::Vec3d(1,0,0), dir);
}
}
else
{
//Fall back on using the center
position = lineString->getBounds().center();
}
}
else
{
position = geom->getBounds().center();
}
}
osgText::Text* t = new osgText::Text();
t->setText( text );
std::string font = "fonts/arial.ttf";
if (symbol->font().isSet() && !symbol->font().get().empty())
{
font = symbol->font().value();
}
t->setFont( font );
t->setAutoRotateToScreen( rotateToScreen );
TextSymbol::SizeMode sizeMode = symbol->sizeMode().isSet() ? symbol->sizeMode().get() : TextSymbol::SIZEMODE_SCREEN;
if (sizeMode == TextSymbol::SIZEMODE_SCREEN) {
t->setCharacterSizeMode( osgText::TextBase::SCREEN_COORDS );
}
else if (sizeMode == TextSymbol::SIZEMODE_OBJECT) {
t->setCharacterSizeMode( osgText::TextBase::OBJECT_COORDS );
}
float size = symbol->size().isSet() ? symbol->size().get() : 32.0f;
t->setCharacterSize( size );
/*
//TODO: We need to do something to account for autotransformed text that is under a LOD. Setting the initial bound works sometimes but not all the time.
if (rotateToScreen)
{
//Set the initial bound so that OSG will traverse the text even if it's under an LOD.
osg::BoundingBox bb;
bb.expandBy( osg::BoundingSphere(position, size));
t->setInitialBound( bb);
}*/
//t->setCharacterSizeMode( osgText::TextBase::OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT );
//t->setCharacterSize( 300000.0f );
t->setPosition( position );
t->setRotation( orientation);
t->setAlignment( osgText::TextBase::CENTER_CENTER );
t->getOrCreateStateSet()->setAttributeAndModes( new osg::Depth(osg::Depth::ALWAYS), osg::StateAttribute::ON );
t->getOrCreateStateSet()->setRenderBinDetails( 99999, "RenderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS );
// apply styling as appropriate:
osg::Vec4f textColor = symbol->fill()->color();
osg::Vec4f haloColor = symbol->halo()->color();
t->setColor( textColor );
t->setBackdropColor( haloColor );
t->setBackdropType( osgText::Text::OUTLINE );
if ( context.isGeocentric() )
{
// install a cluster culler
t->setCullCallback( new CullDrawableByNormal(position * context.inverseReferenceFrame()) );
}
if (_hideClutter)
{
osg::BoundingBox tBound = t->getBound();
osg::ref_ptr<osgUtil::PolytopeIntersector> intersector = new osgUtil::PolytopeIntersector(osgUtil::Intersector::MODEL, tBound.xMin(), tBound.yMin(), tBound.xMax(), tBound.yMax());
osgUtil::IntersectionVisitor intersectVisitor(intersector.get());
result->accept(intersectVisitor);
if (!intersector->containsIntersections())
{
result->addDrawable( t );
if (removeDuplicateLabels) labelNames.insert(text);
}
}
else
{
result->addDrawable( t );
if (removeDuplicateLabels) labelNames.insert(text);
}
}
return result;
}
Here is the call graph for this function:bool osgEarth::Features::BuildTextOperator::_hideClutter [protected] |
Definition at line 45 of file BuildTextOperator.
1.7.3