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;
}