osgEarth 2.1.1
|
Public Member Functions | |
StencilVolumeNodeFactory (const FeatureStencilModelOptions &options, int renderBinStart) | |
bool | createOrUpdateNode (FeatureCursor *cursor, const Style &style, const FilterContext &context, osg::ref_ptr< osg::Node > &node) |
osg::Group * | getOrCreateStyleGroup (const Style &style, Session *session) |
Protected Attributes | |
const FeatureStencilModelOptions | _options |
int | _renderBinStart |
BuildData | _buildData |
Definition at line 351 of file FeatureStencilModelSource.cpp.
anonymous_namespace{FeatureStencilModelSource.cpp}::StencilVolumeNodeFactory::StencilVolumeNodeFactory | ( | const FeatureStencilModelOptions & | options, |
int | renderBinStart | ||
) | [inline] |
Definition at line 359 of file FeatureStencilModelSource.cpp.
: _options(options), _buildData( renderBinStart ) { }
bool anonymous_namespace{FeatureStencilModelSource.cpp}::StencilVolumeNodeFactory::createOrUpdateNode | ( | FeatureCursor * | cursor, |
const Style & | style, | ||
const FilterContext & | context, | ||
osg::ref_ptr< osg::Node > & | node | ||
) | [inline, virtual] |
Render (or update) a list of features into a node according to the specified style.
Implements osgEarth::Features::FeatureNodeFactory.
Definition at line 365 of file FeatureStencilModelSource.cpp.
{ const MapInfo& mi = context.getSession()->getMapInfo(); // A processing context to use locally FilterContext cx = context; // make a working copy of the feature data. FeatureList featureList; cursor->fill( featureList ); //for (FeatureList::const_iterator it = features.begin(); it != features.end(); ++it) // featureList.push_back(osg::clone((*it).get(),osg::CopyOp::DEEP_COPY_ALL)); // establish the extrusion distance for the stencil volumes double extrusionDistance = 1; double densificationThreshold = 1.0; if ( _options.extrusionDistance().isSet() ) { extrusionDistance = *_options.extrusionDistance(); } else { if ( mi.isGeocentric() ) extrusionDistance = 300000.0; // meters geocentric else if ( mi.getProfile()->getSRS()->isGeographic() ) extrusionDistance = 5.0; // degrees-as-meters else extrusionDistance = 12000.0; // meters } densificationThreshold = *_options.densificationThreshold(); // Scan the geometry to see if it includes line data, since that will require buffering: bool hasLines = false; for( FeatureList::const_iterator i = featureList.begin(); i != featureList.end(); ++i ) { Feature* feature = (*i).get(); Geometry* geom = feature->getGeometry(); if ( geom && ( geom->getComponentType() == Geometry::TYPE_LINESTRING || geom->getComponentType() == Geometry::TYPE_RING ) ) { hasLines = true; break; } } // If the geometry is lines, we need to buffer them before they will work with stenciling if ( hasLines ) { const LineSymbol* line = style.getSymbol<LineSymbol>(); if (line) { BufferFilter buffer; buffer.distance() = 0.5 * line->stroke()->width().value(); buffer.capStyle() = line->stroke()->lineCap().value(); cx = buffer.push( featureList, cx ); } } // Transform them into the map's SRS, localizing the verts along the way: TransformFilter xform( mi.getProfile()->getSRS() ); xform.setMakeGeocentric( mi.isGeocentric() ); xform.setLocalizeCoordinates( !mi.isGeocentric() ); cx = xform.push( featureList, cx ); if ( mi.isGeocentric() ) { // We need to make sure that on a round globe, the points are sampled such that // long segments follow the curvature of the earth. By the way, if a Buffer was // applied, that will also remove colinear segment points. Resample the points to // achieve a usable tesselation. ResampleFilter resample; resample.maxLength() = densificationThreshold; resample.minLength() = 0.0; resample.perturbationThreshold() = 0.1; cx = resample.push( featureList, cx ); } // Extrude and cap the geometry in both directions to build a stencil volume: osg::Group* volumes = 0L; for( FeatureList::iterator i = featureList.begin(); i != featureList.end(); ++i ) { Feature* feature = (*i).get(); Geometry* geom = feature->getGeometry(); osg::Node* volume = createVolume( geom, -extrusionDistance, extrusionDistance * 2.0, cx ); if ( volume ) { if ( !volumes ) volumes = new osg::Group(); volumes->addChild( volume ); } } if ( volumes ) { // Resolve the localizing reference frame if necessary: if ( cx.hasReferenceFrame() ) { osg::MatrixTransform* xform = new osg::MatrixTransform( cx.inverseReferenceFrame() ); xform->addChild( volumes ); volumes = xform; } // Apply an LOD if required: if ( _options.minRange().isSet() || _options.maxRange().isSet() ) { osg::LOD* lod = new osg::LOD(); lod->addChild( volumes, _options.minRange().value(), _options.maxRange().value() ); volumes = lod; } // Add the volumes to the appropriate style group. StencilVolumeNode* styleNode = dynamic_cast<StencilVolumeNode*>( getOrCreateStyleGroup( style, cx.getSession() ) ); styleNode->addVolumes( volumes ); } node = 0L; // always return null, since we added our geom to the style group. return volumes != 0L; }
osg::Group* anonymous_namespace{FeatureStencilModelSource.cpp}::StencilVolumeNodeFactory::getOrCreateStyleGroup | ( | const Style & | style, |
Session * | session | ||
) | [inline, virtual] |
Creates a group that will contain all the geometry corresponding to a given style. The subclass has the option of overriding this in order to create a custom implementation.
Reimplemented from osgEarth::Features::FeatureNodeFactory.
Definition at line 494 of file FeatureStencilModelSource.cpp.
{ if ( _options.showVolumes() == true ) { return new osg::Group(); } else { StencilVolumeNode* styleNode = 0L; if ( !_buildData.getStyleNode(style.getName(), styleNode, true) ) { // did not find; write-lock it and try again (double-check pattern) Threading::ScopedWriteLock exclusiveLock( _buildData._mutex ); if ( !_buildData.getStyleNode(style.getName(), styleNode, false) ) { OE_INFO << LC << "Create style group \"" << style.getName() << "\"" << std::endl; styleNode = new StencilVolumeNode( *_options.mask(), *_options.inverted() ); if ( _options.mask() == false ) { osg::Vec4f maskColor = osg::Vec4(1,1,0,1); if (/*hasLines &&*/ style.getSymbol<LineSymbol>()) { const LineSymbol* line = style.getSymbol<LineSymbol>(); maskColor = line->stroke()->color(); } else { const PolygonSymbol* poly = style.getSymbol<PolygonSymbol>(); if (poly) maskColor = poly->fill()->color(); } styleNode->addChild( createColorNode(maskColor) ); osg::StateSet* ss = styleNode->getOrCreateStateSet(); ss->setMode( GL_LIGHTING, _options.enableLighting() == true? osg::StateAttribute::ON | osg::StateAttribute::PROTECTED : osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); } _buildData._renderBin = styleNode->setBaseRenderBin( _buildData._renderBin ); _buildData._styleGroups.push_back( BuildData::StyleGroup(style.getName(), styleNode) ); } } return styleNode; } }
BuildData anonymous_namespace{FeatureStencilModelSource.cpp}::StencilVolumeNodeFactory::_buildData [protected] |
Definition at line 356 of file FeatureStencilModelSource.cpp.
const FeatureStencilModelOptions anonymous_namespace{FeatureStencilModelSource.cpp}::StencilVolumeNodeFactory::_options [protected] |
Definition at line 354 of file FeatureStencilModelSource.cpp.
int anonymous_namespace{FeatureStencilModelSource.cpp}::StencilVolumeNodeFactory::_renderBinStart [protected] |
Definition at line 355 of file FeatureStencilModelSource.cpp.