bool BuildGeometryFilter::pushRegularFeature( Feature* input, const FilterContext& context ) { GeometryIterator parts( input->getGeometry(), false ); while( parts.hasMore() ) { Geometry* part = parts.next(); osg::PrimitiveSet::Mode primMode = osg::PrimitiveSet::POINTS; const Style& myStyle = input->style().isSet() ? *input->style() : _style; //const Style* myStyle = input->style().isSet() ? input->style()->get() : _style.get(); osg::Vec4f color = osg::Vec4(1,1,1,1); bool tessellatePolys = true; bool setWidth = input->style().isSet(); // otherwise it will be set globally, we assume float width = 1.0f; switch( part->getType() ) { case Geometry::TYPE_POINTSET: { _hasPoints = true; primMode = osg::PrimitiveSet::POINTS; const PointSymbol* point = myStyle.getSymbol<PointSymbol>(); if (point) { color = point->fill()->color(); } } break; case Geometry::TYPE_LINESTRING: { _hasLines = true; primMode = osg::PrimitiveSet::LINE_STRIP; const LineSymbol* lineSymbol = myStyle.getSymbol<LineSymbol>(); if (lineSymbol) { color = lineSymbol->stroke()->color(); width = lineSymbol->stroke()->width().isSet() ? *lineSymbol->stroke()->width() : 1.0f; } } break; case Geometry::TYPE_RING: { _hasLines = true; primMode = osg::PrimitiveSet::LINE_LOOP; const LineSymbol* lineSymbol = myStyle.getSymbol<LineSymbol>(); if (lineSymbol) { color = lineSymbol->stroke()->color(); width = lineSymbol->stroke()->width().isSet() ? *lineSymbol->stroke()->width() : 1.0f; } } break; case Geometry::TYPE_POLYGON: { primMode = osg::PrimitiveSet::LINE_LOOP; // loop will tessellate into polys const PolygonSymbol* poly = myStyle.getSymbol<PolygonSymbol>(); if (poly) { _hasPolygons = true; color = poly->fill()->color(); } else { // if we have a line symbol and no polygon symbol, draw as an outline. _hasLines = true; const LineSymbol* line = myStyle.getSymbol<LineSymbol>(); if ( line ) { color = line->stroke()->color(); width = line->stroke()->width().isSet() ? *line->stroke()->width() : 1.0f; tessellatePolys = false; } } } break; } osg::Geometry* osgGeom = new osg::Geometry(); if ( _featureNameExpr.isSet() ) { const std::string& name = input->eval( _featureNameExpr.mutable_value() ); osgGeom->setName( name ); } osgGeom->setUseVertexBufferObjects( true ); osgGeom->setUseDisplayList( false ); if ( setWidth && width != 1.0f ) { osgGeom->getOrCreateStateSet()->setAttributeAndModes( new osg::LineWidth( width ), osg::StateAttribute::ON ); } if (part->getType() == Geometry::TYPE_POLYGON && static_cast<Polygon*>(part)->getHoles().size() > 0 ) { Polygon* poly = static_cast<Polygon*>(part); int totalPoints = poly->getTotalPointCount(); osg::Vec3Array* allPoints = new osg::Vec3Array( totalPoints ); std::copy( part->begin(), part->end(), allPoints->begin() ); osgGeom->addPrimitiveSet( new osg::DrawArrays( primMode, 0, part->size() ) ); int offset = part->size(); for( RingCollection::const_iterator h = poly->getHoles().begin(); h != poly->getHoles().end(); ++h ) { Geometry* hole = h->get(); if ( hole->isValid() ) { std::copy( hole->begin(), hole->end(), allPoints->begin() + offset ); osgGeom->addPrimitiveSet( new osg::DrawArrays( primMode, offset, hole->size() ) ); offset += hole->size(); } } osgGeom->setVertexArray( allPoints ); } else { osgGeom->setVertexArray( part->toVec3Array() ); osgGeom->addPrimitiveSet( new osg::DrawArrays( primMode, 0, part->size() ) ); } // tessellate all polygon geometries. Tessellating each geometry separately // with TESS_TYPE_GEOMETRY is much faster than doing the whole bunch together // using TESS_TYPE_DRAWABLE. if ( part->getType() == Geometry::TYPE_POLYGON && tessellatePolys ) { osgUtil::Tessellator tess; //tess.setTessellationType( osgUtil::Tessellator::TESS_TYPE_DRAWABLE ); //tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD ); tess.setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY ); tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_POSITIVE ); tess.retessellatePolygons( *osgGeom ); // the tessellator results in a collection of trifans, strips, etc. This step will // consolidate those into one (or more if necessary) GL_TRIANGLES primitive. MeshConsolidator::run( *osgGeom ); // mark this geometry as DYNAMIC because otherwise the OSG optimizer will destroy it. //osgGeom->setDataVariance( osg::Object::DYNAMIC ); } if ( context.isGeocentric() && part->getType() != Geometry::TYPE_POINTSET ) { double threshold = osg::DegreesToRadians( *_maxAngle_deg ); MeshSubdivider ms( context.referenceFrame(), context.inverseReferenceFrame() ); //ms.setMaxElementsPerEBO( INT_MAX ); ms.run( threshold, *osgGeom ); } // set the color array. We have to do this last, otherwise it screws up any modifications // make by the MeshSubdivider. No idea why. gw //osg::Vec4Array* colors = new osg::Vec4Array( osgGeom->getVertexArray()->getNumElements() ); //for( unsigned c = 0; c < colors->size(); ++c ) // (*colors)[c] = color; //osgGeom->setColorArray( colors ); //osgGeom->setColorBinding( osg::Geometry::BIND_PER_VERTEX ); // NOTE! per-vertex colors makes the optimizer destroy the geometry.... osg::Vec4Array* colors = new osg::Vec4Array(1); (*colors)[0] = color; osgGeom->setColorArray( colors ); osgGeom->setColorBinding( osg::Geometry::BIND_OVERALL ); // add the part to the geode. _geode->addDrawable( osgGeom ); } return true; }