• osgEarth2.8加载矢量数据描边效果


    通过修改osgearth自带的agglite插件,实现矢量描边效果,可以自定义描边的颜色和宽度(单位像素)

    测试文件osgearth_features.cpp

    #include <osg/Notify>
    #include <osgGA/StateSetManipulator>
    #include <osgViewer/Viewer>
    #include <osgViewer/ViewerEventHandlers>
    #include <osgEarth/Map>
    #include <osgEarth/MapNode>
    #include <osgEarthUtil/ExampleResources>
    #include <osgEarthUtil/EarthManipulator>
    #include <osgEarthUtil/AutoClipPlaneHandler>
    
    #include <osgEarthSymbology/Style>
    #include <osgEarthFeatures/ConvertTypeFilter>
    
    #include <osgEarthDrivers/gdal/GDALOptions>
    #include <osgEarthDrivers/feature_ogr/OGRFeatureOptions>
    #include "AGGLiteOptions2"
    #include <osgEarthDrivers/model_feature_geom/FeatureGeomModelOptions>
    
    #include <osgDB/WriteFile>
    
    #ifdef _DEBUG
    #pragma comment(lib, "osgd.lib")
    #pragma comment(lib, "osgDBd.lib")
    #pragma comment(lib, "osgViewerd.lib")
    #pragma comment(lib, "osgGAd.lib")
    #pragma comment(lib, "osgEarthd.lib")
    #pragma comment(lib, "osgEarthSymbologyd.lib")
    #pragma comment(lib, "osgEarthUtild.lib")
    #pragma comment(lib, "osgEarthFeaturesd.lib")
    #else
    #pragma comment(lib, "osg.lib")
    #pragma comment(lib, "osgDB.lib")
    #pragma comment(lib, "osgViewer.lib")
    #pragma comment(lib, "osgGA.lib")
    #pragma comment(lib, "osgEarth.lib")
    #pragma comment(lib, "osgEarthSymbology.lib")
    #pragma comment(lib, "osgEarthUtil.lib")
    #pragma comment(lib, "osgEarthFeatures.lib")
    #endif // DEBUG
    
    using namespace osgEarth;
    using namespace osgEarth::Features;
    using namespace osgEarth::Drivers;
    using namespace osgEarth::Symbology;
    using namespace osgEarth::Util;
    
    //
    // NOTE: run this sample from the repo/tests directory.
    //
    int main(int argc, char** argv)
    {
        osg::ArgumentParser arguments(&argc, argv);
        osgViewer::Viewer viewer(arguments);
    
        // Start by creating the map:
        Map* map = new Map();
    
        // Start with a basemap imagery layer; we'll be using the GDAL driver
        // to load a local GeoTIFF file:
        GDALOptions basemapOpt;
        basemapOpt.url() = "world.tif";
        map->addImageLayer(new ImageLayer(ImageLayerOptions("basemap", basemapOpt)));
    
        // Next we add a feature layer. 
        OGRFeatureOptions featureOptions;
        // Configures the feature driver to load the vectors from a shapefile:
        featureOptions.url() = "world.shp";
    
        
    
        // That's it, the map is ready; now create a MapNode to render the Map:
        MapNodeOptions mapNodeOptions;
        mapNodeOptions.enableLighting() = false;
        MapNode* mapNode = new MapNode(map, mapNodeOptions);
    
        osg::Group* root = new osg::Group();
        root->addChild(mapNode);
        viewer.setSceneData(root);
        viewer.setCameraManipulator(new EarthManipulator());
    
        // Process cmdline args
        MapNodeHelper().parse(mapNode, arguments, &viewer, root, new LabelControl("Features Demo"));
    
        // Define a style for the feature data. Since we are going to render the
        // vectors as lines, configure the line symbolizer:
        Style style;
        LineSymbol* ls = style.getOrCreateSymbol<LineSymbol>();
        ls->stroke()->color() = Color::Yellow;
        ls->stroke()->width() = 6.0f;
        ls->stroke()->lineCap() = osgEarth::Symbology::Stroke::LINECAP_ROUND;//使连接处圆滑一些
    
        AGGLiteOptions2 rasterOptions;
        rasterOptions.featureOptions() = featureOptions;
        rasterOptions.styles() = new StyleSheet();
        rasterOptions.styles()->addStyle(style);
        rasterOptions.borderColor() = Color::Red;//包边颜色
        rasterOptions.borderWidth() = 3.0f;//包边宽度(单位像素)
        map->addImageLayer(new ImageLayer("my features", rasterOptions));
    
        // add some stock OSG handlers:
        viewer.addEventHandler(new osgViewer::StatsHandler());
        viewer.addEventHandler(new osgViewer::WindowSizeHandler());
        viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
        viewer.setUpViewInWindow(100, 500, 800, 600);
        return viewer.run();
    }

    头文件AGGLiteOptions2

    #ifndef OSGEARTH_DRIVER_AGGLITE2_DRIVEROPTIONS
    #define OSGEARTH_DRIVER_AGGLITE2_DRIVEROPTIONS 1
    
    #include <osgEarth/Common>
    #include <osgEarthFeatures/FeatureTileSource>
    
    namespace osgEarth { namespace Drivers
    {
        using namespace osgEarth;
        using namespace osgEarth::Features;
    
        class AGGLiteOptions2 : public FeatureTileSourceOptions // NO EXPORT; header only
        {
        public:
            /** 
             * Whether to downsample line features to that they are no higher resolution than
             * the target image resolution. Defaults to true, but you can disable this (for a possible
             * performance increase) if you know your data to be of a relatively low resolution.
             * (Default = true)
             */
            optional<bool>& optimizeLineSampling() { return _optimizeLineSampling; }
            const optional<bool>& optimizeLineSampling() const { return _optimizeLineSampling; }
    
            /** 
             * Set the gamma parameter applied on the AggLite rasterizer : allow to control geometry antialiasing
             * (Default = 1.3)
             */
            optional<double>& gamma() { return _gamma; }
            const optional<double>& gamma() const { return _gamma; }
    
            //w.g.描边的颜色和宽度(单位像素)
            /** Border color. */
            Color& borderColor() { return _borderColor; }
            const Color& borderColor() const { return _borderColor; }
            /** Line border rendering width. */
            optional<double>& borderWidth() { return _borderWidth; }
            const optional<double>& borderWidth() const { return _borderWidth; }
    
        public:
            AGGLiteOptions2( const TileSourceOptions& options =TileSourceOptions() )
                : FeatureTileSourceOptions( options ),
                  _optimizeLineSampling   ( true ),
                  _gamma                  ( 1.3 ),
                _borderColor(Color::White),
                _borderWidth(1)
            {
                setDriver( "agglite2" );
                fromConfig( _conf );
            }
    
            /** dtor */
            virtual ~AGGLiteOptions2() { }
    
        public:
            Config getConfig() const {
                Config conf = FeatureTileSourceOptions::getConfig();
                conf.updateIfSet("optimize_line_sampling", _optimizeLineSampling);
                conf.updateIfSet("gamma", _gamma );
                conf.add("borderColor", _borderColor.toHTML());
                conf.updateIfSet("borderWidth", _borderWidth);
                return conf;
            }
    
        protected:
            void mergeConfig( const Config& conf ) {
                FeatureTileSourceOptions::mergeConfig( conf );
                fromConfig(conf);
            }
    
        private:
            void fromConfig( const Config& conf ) {
                conf.getIfSet( "optimize_line_sampling", _optimizeLineSampling );
                conf.getIfSet( "gamma", _gamma );
                _borderColor = Color(conf.value("borderColor"));
                conf.getIfSet("borderWidth", _borderWidth);
            }
    
            optional<bool>   _optimizeLineSampling;
            optional<double> _gamma;
            //w.g.描边的颜色和宽度(单位像素)
            Color            _borderColor;
            optional<double>  _borderWidth;
        };
    
    } } // namespace osgEarth::Drivers
    
    #endif // OSGEARTH_DRIVER_AGGLITE2_DRIVEROPTIONS

    插件文件AGGLiteRasterizerTileSource2.cpp

    #include <osgEarthFeatures/FeatureTileSource>
    #include <osgEarthFeatures/ResampleFilter>
    #include <osgEarthFeatures/TransformFilter>
    #include <osgEarthFeatures/BufferFilter>
    #include <osgEarthSymbology/Style>
    //TODO: replace this with GeometryRasterizer
    #include <osgEarthSymbology/AGG.h>
    #include <osgEarth/Registry>
    #include <osgEarth/FileUtils>
    #include <osgEarth/ImageUtils>
    
    #include <osg/Notify>
    #include <osgDB/FileNameUtils>
    #include <osgDB/FileUtils>
    #include <osgDB/Registry>
    #include <osgDB/ReadFile>
    #include <osgDB/WriteFile>
    
    #include "AGGLiteOptions2"
    
    #include <sstream>
    #include <OpenThreads/Mutex>
    #include <OpenThreads/ScopedLock>
    
    #define LC "[AGGLite2] "
    
    using namespace osgEarth;
    using namespace osgEarth::Features;
    using namespace osgEarth::Symbology;
    using namespace osgEarth::Drivers;
    using namespace OpenThreads;
    
    namespace
    {
        struct float32
        {
            float32() : value(NO_DATA_VALUE) { }
            float32(float v) : value(v) { }
    
            float value;
        };
    
        struct span_coverage32
        {
            static void render(unsigned char* ptr, 
                               int x,
                               unsigned count, 
                               const unsigned char* covers, 
                               const float32& c)
            {
                unsigned char* p = ptr + (x << 2);
                float* f = (float*)p;
                do
                {
                    unsigned char cover = *covers++;
                    int hasData = cover > 127;
                    *f++ = hasData ? c.value : NO_DATA_VALUE;
                }
                while(--count);
            }
    
            static void hline(unsigned char* ptr, 
                              int x,
                              unsigned count, 
                              const float32& c)
            {
                unsigned char* p = ptr + (x << 2);
                float* f = (float*)p;
                do {
                    *f++ = c.value;
                }
                while(--count);
            }
    
            static float32 get(unsigned char* ptr, int x)
            {
                unsigned char* p = ptr + (x << 2);
                float* f = (float*)p;
                return float32(*f);
            }
        };
    }
    
    /********************************************************************/
    
    class AGGLiteRasterizerTileSource2 : public FeatureTileSource
    {
    public:
        struct RenderFrame {
            double xmin, ymin;
            double xf, yf;
        };
    
    public:
        AGGLiteRasterizerTileSource2( const TileSourceOptions& options ) : FeatureTileSource( options ),
            _options( options )
        {
            //nop
        }
    
        //override
        osg::Image* allocateImage()
        {
            osg::Image* image = 0L;
            if ( _options.coverage() == true )
            {
                image = new osg::Image();
                image->allocateImage(getPixelsPerTile(), getPixelsPerTile(), 1, GL_LUMINANCE, GL_FLOAT);
                image->setInternalTextureFormat(GL_LUMINANCE32F_ARB);
                ImageUtils::markAsUnNormalized(image, true);
            }
            return image;
        }
    
        //override
        bool preProcess(osg::Image* image, osg::Referenced* buildData)
        {
            agg::rendering_buffer rbuf( image->data(), image->s(), image->t(), image->s()*4 );
    
            // clear the buffer.
            if ( _options.coverage() == true )
            {
                // For coverage data, FLT_MAX = no data.
                agg::renderer<span_coverage32, float32> ren(rbuf);
                ren.clear( float32(NO_DATA_VALUE) );
            }
            else
            {
                agg::renderer<agg::span_abgr32, agg::rgba8> ren(rbuf);
                ren.clear(agg::rgba8(0,0,0,0));
            }
            return true;
        }
    
        //override
        bool renderFeaturesForStyle(
            Session*           session,
            const Style&       style,
            const FeatureList& features,
            osg::Referenced*   buildData,
            const GeoExtent&   imageExtent,
            osg::Image*        image )
        {
            //w.g.先绘制描边
            renderFeaturesForStyle2(session, style, features, buildData, imageExtent, image);
    
            OE_DEBUG << LC << "Rendering " << features.size() << " features for " << imageExtent.toString() << "
    ";
    
            // A processing context to use with the filters:
            FilterContext context( session );
            context.setProfile( getFeatureSource()->getFeatureProfile() );
    
            const LineSymbol*    masterLine = style.getSymbol<LineSymbol>();
            const PolygonSymbol* masterPoly = style.getSymbol<PolygonSymbol>();
            const CoverageSymbol* masterCov = style.getSymbol<CoverageSymbol>();
    
            // sort into bins, making a copy for lines that require buffering.
            FeatureList polygons;
            FeatureList lines;
    
            for(FeatureList::const_iterator f = features.begin(); f != features.end(); ++f)
            {
                if ( f->get()->getGeometry() )
                {
                    bool hasPoly = false;
                    bool hasLine = false;
    
                    if ( masterPoly || f->get()->style()->has<PolygonSymbol>() )
                    {
                        polygons.push_back( f->get() );
                        hasPoly = true;
                    }
    
                    if ( masterLine || f->get()->style()->has<LineSymbol>() )
                    {
                        Feature* newFeature = new Feature( *f->get() );
                        if ( !newFeature->getGeometry()->isLinear() )
                        {
                            newFeature->setGeometry( newFeature->getGeometry()->cloneAs(Geometry::TYPE_RING) );
                        }
                        lines.push_back( newFeature );
                        hasLine = true;
                    }
    
                    // if there are no geometry symbols but there is a coverage symbol, default to polygons.
                    if ( !hasLine && !hasPoly )
                    {
                        if ( masterCov || f->get()->style()->has<CoverageSymbol>() )
                        {
                            polygons.push_back( f->get() );
                        }
                    }
                }
            }
    
            // initialize:
            RenderFrame frame;
            frame.xmin = imageExtent.xMin();
            frame.ymin = imageExtent.yMin();
            frame.xf   = (double)image->s() / imageExtent.width();
            frame.yf   = (double)image->t() / imageExtent.height();
    
            if ( lines.size() > 0 )
            {
                // We are buffering in the features native extent, so we need to use the
                // transformed extent to get the proper "resolution" for the image
                const SpatialReference* featureSRS = context.profile()->getSRS();
                GeoExtent transformedExtent = imageExtent.transform(featureSRS);
    
                double trans_xf = (double)image->s() / transformedExtent.width();
                double trans_yf = (double)image->t() / transformedExtent.height();
    
                // resolution of the image (pixel extents):
                double xres = 1.0/trans_xf;
                double yres = 1.0/trans_yf;
    
                // downsample the line data so that it is no higher resolution than to image to which
                // we intend to rasterize it. If you don't do this, you run the risk of the buffer 
                // operation taking forever on very high-res input data.
                if ( _options.optimizeLineSampling() == true )
                {
                    ResampleFilter resample;
                    resample.minLength() = osg::minimum( xres, yres );
                    context = resample.push( lines, context );
                }
    
                // now run the buffer operation on all lines:
                BufferFilter buffer;
                double lineWidth = 1.0;
                if ( masterLine )
                {
                    buffer.capStyle() = masterLine->stroke()->lineCap().value();
    
                    if ( masterLine->stroke()->width().isSet() )
                    {
                        lineWidth = masterLine->stroke()->width().value();
    
                        GeoExtent imageExtentInFeatureSRS = imageExtent.transform(featureSRS);
                        double pixelWidth = imageExtentInFeatureSRS.width() / (double)image->s();
    
                        // if the width units are specified, process them:
                        if (masterLine->stroke()->widthUnits().isSet() &&
                            masterLine->stroke()->widthUnits().get() != Units::PIXELS)
                        {
                            const Units& featureUnits = featureSRS->getUnits();
                            const Units& strokeUnits  = masterLine->stroke()->widthUnits().value();
    
                            // if the units are different than those of the feature data, we need to
                            // do a units conversion.
                            if ( featureUnits != strokeUnits )
                            {
                                if ( Units::canConvert(strokeUnits, featureUnits) )
                                {
                                    // linear to linear, no problem
                                    lineWidth = strokeUnits.convertTo( featureUnits, lineWidth );
                                }
                                else if ( strokeUnits.isLinear() && featureUnits.isAngular() )
                                {
                                    // linear to angular? approximate degrees per meter at the 
                                    // latitude of the tile's centroid.
                                    double lineWidthM = masterLine->stroke()->widthUnits()->convertTo(Units::METERS, lineWidth);
                                    double mPerDegAtEquatorInv = 360.0/(featureSRS->getEllipsoid()->getRadiusEquator() * 2.0 * osg::PI);
                                    double lon, lat;
                                    imageExtent.getCentroid(lon, lat);
                                    lineWidth = lineWidthM * mPerDegAtEquatorInv * cos(osg::DegreesToRadians(lat));
                                }
                            }
    
                            // enfore a minimum width of one pixel.
                            float minPixels = masterLine->stroke()->minPixels().getOrUse( 1.0f );
                            lineWidth = osg::clampAbove(lineWidth, pixelWidth*minPixels);
                        }
    
                        else // pixels
                        {
                            lineWidth *= pixelWidth;
                        }
                    }
                }
    
                buffer.distance() = lineWidth * 0.5;   // since the distance is for one side
                buffer.push( lines, context );
            }
    
            // Transform the features into the map's SRS:
            TransformFilter xform( imageExtent.getSRS() );
            xform.setLocalizeCoordinates( false );
            FilterContext polysContext = xform.push( polygons, context );
            FilterContext linesContext = xform.push( lines, context );
    
            // set up the AGG renderer:
            agg::rendering_buffer rbuf( image->data(), image->s(), image->t(), image->s()*4 );
    
            // Create the renderer and the rasterizer
            agg::rasterizer ras;
    
            // Setup the rasterizer
            if ( _options.coverage() == true )
                ras.gamma(1.0);
            else
                ras.gamma(_options.gamma().get());
    
            ras.filling_rule(agg::fill_even_odd);
    
            // construct an extent for cropping the geometry to our tile.
            // extend just outside the actual extents so we don't get edge artifacts:
            GeoExtent cropExtent = GeoExtent(imageExtent);
            cropExtent.scale(1.1, 1.1);
    
            osg::ref_ptr<Symbology::Polygon> cropPoly = new Symbology::Polygon( 4 );
            cropPoly->push_back( osg::Vec3d( cropExtent.xMin(), cropExtent.yMin(), 0 ));
            cropPoly->push_back( osg::Vec3d( cropExtent.xMax(), cropExtent.yMin(), 0 ));
            cropPoly->push_back( osg::Vec3d( cropExtent.xMax(), cropExtent.yMax(), 0 ));
            cropPoly->push_back( osg::Vec3d( cropExtent.xMin(), cropExtent.yMax(), 0 ));
    
            // If there's a coverage symbol, make a copy of the expressions so we can evaluate them
            optional<NumericExpression> covValue;
            const CoverageSymbol* covsym = style.get<CoverageSymbol>();
            if (covsym && covsym->valueExpression().isSet())
                covValue = covsym->valueExpression().get();
    
            // render the polygons
            for(FeatureList::iterator i = polygons.begin(); i != polygons.end(); i++)
            {
                Feature*  feature  = i->get();
                Geometry* geometry = feature->getGeometry();
    
                osg::ref_ptr<Geometry> croppedGeometry;
                if ( geometry->crop( cropPoly.get(), croppedGeometry ) )
                {
                    const PolygonSymbol* poly =
                        feature->style().isSet() && feature->style()->has<PolygonSymbol>() ? feature->style()->get<PolygonSymbol>() :
                        masterPoly;
    
                    if ( _options.coverage() == true && covValue.isSet() )
                    {
                        float value = (float)feature->eval(covValue.mutable_value(), &context);
                        rasterizeCoverage(croppedGeometry.get(), value, frame, ras, rbuf);
                    }
                    else
                    {
                        osg::Vec4f color = poly->fill()->color();
                        rasterize(croppedGeometry.get(), color, frame, ras, rbuf);
                    }
                    
                }
            }
    
            // render the lines
            for(FeatureList::iterator i = lines.begin(); i != lines.end(); i++)
            {
                Feature*  feature  = i->get();
                Geometry* geometry = feature->getGeometry();
    
                osg::ref_ptr<Geometry> croppedGeometry;
                if ( geometry->crop( cropPoly.get(), croppedGeometry ) )
                {
                    const LineSymbol* line =
                        feature->style().isSet() && feature->style()->has<LineSymbol>() ? feature->style()->get<LineSymbol>() :
                        masterLine;
    
                    if ( _options.coverage() == true && covValue.isSet() )
                    {
                        float value = (float)feature->eval(covValue.mutable_value(), &context);
                        rasterizeCoverage(croppedGeometry.get(), value, frame, ras, rbuf);
                    }
                    else
                    {   osg::Vec4f color = line ? static_cast<osg::Vec4>(line->stroke()->color()) : osg::Vec4(1,1,1,1);
                        rasterize(croppedGeometry.get(), color, frame, ras, rbuf);
                    }
                }
            }
    
            return true;
        }
    
        //w.g.描边
        bool renderFeaturesForStyle2(
            Session*           session,
            const Style&       style,
            const FeatureList& features,
            osg::Referenced*   buildData,
            const GeoExtent&   imageExtent,
            osg::Image*        image)
        {
            OE_DEBUG << LC << "Rendering " << features.size() << " features for " << imageExtent.toString() << "
    ";
    
            // A processing context to use with the filters:
            FilterContext context(session);
            context.setProfile(getFeatureSource()->getFeatureProfile());
    
            const LineSymbol*    masterLine = style.getSymbol<LineSymbol>();
            const PolygonSymbol* masterPoly = style.getSymbol<PolygonSymbol>();
            const CoverageSymbol* masterCov = style.getSymbol<CoverageSymbol>();
    
            // sort into bins, making a copy for lines that require buffering.
            FeatureList polygons;
            FeatureList lines;
    
            for (FeatureList::const_iterator f = features.begin(); f != features.end(); ++f)
            {
                if (f->get()->getGeometry())
                {
                    bool hasPoly = false;
                    bool hasLine = false;
    
                    if (masterPoly || f->get()->style()->has<PolygonSymbol>())
                    {
                        polygons.push_back(f->get());
                        hasPoly = true;
                    }
    
                    if (masterLine || f->get()->style()->has<LineSymbol>())
                    {
                        Feature* newFeature = new Feature(*f->get());
                        if (!newFeature->getGeometry()->isLinear())
                        {
                            newFeature->setGeometry(newFeature->getGeometry()->cloneAs(Geometry::TYPE_RING));
                        }
                        lines.push_back(newFeature);
                        hasLine = true;
                    }
    
                    // if there are no geometry symbols but there is a coverage symbol, default to polygons.
                    if (!hasLine && !hasPoly)
                    {
                        if (masterCov || f->get()->style()->has<CoverageSymbol>())
                        {
                            polygons.push_back(f->get());
                        }
                    }
                }
            }
    
            // initialize:
            RenderFrame frame;
            frame.xmin = imageExtent.xMin();
            frame.ymin = imageExtent.yMin();
            frame.xf = (double)image->s() / imageExtent.width();
            frame.yf = (double)image->t() / imageExtent.height();
    
            if (lines.size() > 0)
            {
                // We are buffering in the features native extent, so we need to use the
                // transformed extent to get the proper "resolution" for the image
                const SpatialReference* featureSRS = context.profile()->getSRS();
                GeoExtent transformedExtent = imageExtent.transform(featureSRS);
    
                double trans_xf = (double)image->s() / transformedExtent.width();
                double trans_yf = (double)image->t() / transformedExtent.height();
    
                // resolution of the image (pixel extents):
                double xres = 1.0 / trans_xf;
                double yres = 1.0 / trans_yf;
    
                // downsample the line data so that it is no higher resolution than to image to which
                // we intend to rasterize it. If you don't do this, you run the risk of the buffer 
                // operation taking forever on very high-res input data.
                if (_options.optimizeLineSampling() == true)
                {
                    ResampleFilter resample;
                    resample.minLength() = osg::minimum(xres, yres);
                    context = resample.push(lines, context);
                }
    
                // now run the buffer operation on all lines:
                BufferFilter buffer;
                double lineWidth = 1.0;
                if (masterLine)
                {
                    buffer.capStyle() = masterLine->stroke()->lineCap().value();
    
                    if (masterLine->stroke()->width().isSet())
                    {
                        //w.g.描边的宽度(单位像素)
                        lineWidth = masterLine->stroke()->width().value()+_options.borderWidth().value()*2;
    
                        GeoExtent imageExtentInFeatureSRS = imageExtent.transform(featureSRS);
                        double pixelWidth = imageExtentInFeatureSRS.width() / (double)image->s();
    
                        // if the width units are specified, process them:
                        if (masterLine->stroke()->widthUnits().isSet() &&
                            masterLine->stroke()->widthUnits().get() != Units::PIXELS)
                        {
                            const Units& featureUnits = featureSRS->getUnits();
                            const Units& strokeUnits = masterLine->stroke()->widthUnits().value();
    
                            // if the units are different than those of the feature data, we need to
                            // do a units conversion.
                            if (featureUnits != strokeUnits)
                            {
                                if (Units::canConvert(strokeUnits, featureUnits))
                                {
                                    // linear to linear, no problem
                                    lineWidth = strokeUnits.convertTo(featureUnits, lineWidth);
                                }
                                else if (strokeUnits.isLinear() && featureUnits.isAngular())
                                {
                                    // linear to angular? approximate degrees per meter at the 
                                    // latitude of the tile's centroid.
                                    double lineWidthM = masterLine->stroke()->widthUnits()->convertTo(Units::METERS, lineWidth);
                                    double mPerDegAtEquatorInv = 360.0 / (featureSRS->getEllipsoid()->getRadiusEquator() * 2.0 * osg::PI);
                                    double lon, lat;
                                    imageExtent.getCentroid(lon, lat);
                                    lineWidth = lineWidthM * mPerDegAtEquatorInv * cos(osg::DegreesToRadians(lat));
                                }
                            }
    
                            // enfore a minimum width of one pixel.
                            float minPixels = masterLine->stroke()->minPixels().getOrUse(1.0f);
                            lineWidth = osg::clampAbove(lineWidth, pixelWidth*minPixels);
                        }
    
                        else // pixels
                        {
                            lineWidth *= pixelWidth;
                        }
                    }
                }
    
                buffer.distance() = lineWidth*0.5;
                buffer.push(lines, context);
            }
    
            // Transform the features into the map's SRS:
            TransformFilter xform(imageExtent.getSRS());
            xform.setLocalizeCoordinates(false);
            FilterContext polysContext = xform.push(polygons, context);
            FilterContext linesContext = xform.push(lines, context);
    
            // set up the AGG renderer:
            agg::rendering_buffer rbuf(image->data(), image->s(), image->t(), image->s() * 4);
    
            // Create the renderer and the rasterizer
            agg::rasterizer ras;
    
            // Setup the rasterizer
            if (_options.coverage() == true)
                ras.gamma(1.0);
            else
                ras.gamma(_options.gamma().get());
    
            ras.filling_rule(agg::fill_even_odd);
    
            // construct an extent for cropping the geometry to our tile.
            // extend just outside the actual extents so we don't get edge artifacts:
            GeoExtent cropExtent = GeoExtent(imageExtent);
            cropExtent.scale(1.1, 1.1);
    
            osg::ref_ptr<Symbology::Polygon> cropPoly = new Symbology::Polygon(4);
            cropPoly->push_back(osg::Vec3d(cropExtent.xMin(), cropExtent.yMin(), 0));
            cropPoly->push_back(osg::Vec3d(cropExtent.xMax(), cropExtent.yMin(), 0));
            cropPoly->push_back(osg::Vec3d(cropExtent.xMax(), cropExtent.yMax(), 0));
            cropPoly->push_back(osg::Vec3d(cropExtent.xMin(), cropExtent.yMax(), 0));
    
            // If there's a coverage symbol, make a copy of the expressions so we can evaluate them
            optional<NumericExpression> covValue;
            const CoverageSymbol* covsym = style.get<CoverageSymbol>();
            if (covsym && covsym->valueExpression().isSet())
                covValue = covsym->valueExpression().get();
    
            // render the polygons
            for (FeatureList::iterator i = polygons.begin(); i != polygons.end(); i++)
            {
                Feature*  feature = i->get();
                Geometry* geometry = feature->getGeometry();
    
                osg::ref_ptr<Geometry> croppedGeometry;
                if (geometry->crop(cropPoly.get(), croppedGeometry))
                {
                    const PolygonSymbol* poly =
                        feature->style().isSet() && feature->style()->has<PolygonSymbol>() ? feature->style()->get<PolygonSymbol>() :
                        masterPoly;
    
                    if (_options.coverage() == true && covValue.isSet())
                    {
                        float value = (float)feature->eval(covValue.mutable_value(), &context);
                        rasterizeCoverage(croppedGeometry.get(), value, frame, ras, rbuf);
                    }
                    else
                    {
                        osg::Vec4f color = poly->fill()->color();
                        rasterize(croppedGeometry.get(), color, frame, ras, rbuf);
                    }
    
                }
            }
    
            // render the lines
            for (FeatureList::iterator i = lines.begin(); i != lines.end(); i++)
            {
                Feature*  feature = i->get();
                Geometry* geometry = feature->getGeometry();
    
                osg::ref_ptr<Geometry> croppedGeometry;
                if (geometry->crop(cropPoly.get(), croppedGeometry))
                {
                    const LineSymbol* line =
                        feature->style().isSet() && feature->style()->has<LineSymbol>() ? feature->style()->get<LineSymbol>() :
                        masterLine;
    
                    if (_options.coverage() == true && covValue.isSet())
                    {
                        float value = (float)feature->eval(covValue.mutable_value(), &context);
                        rasterizeCoverage(croppedGeometry.get(), value, frame, ras, rbuf);
                    }
                    else
                    {
                        //w.g.描边的颜色
                        osg::Vec4f color = static_cast<osg::Vec4>(_options.borderColor());
                        rasterize(croppedGeometry.get(), color, frame, ras, rbuf);
                    }
                }
            }
    
            return true;
        }
        //override
        bool postProcess( osg::Image* image, osg::Referenced* data )
        {
            if ( _options.coverage() == false )
            {
                //convert from ABGR to RGBA
                unsigned char* pixel = image->data();
                for(int i=0; i<image->s()*image->t()*4; i+=4, pixel+=4)
                {
                    std::swap( pixel[0], pixel[3] );
                    std::swap( pixel[1], pixel[2] );
                }
            }
    
            return true;
        }
    
        // rasterizes a geometry to color
        void rasterize(const Geometry* geometry, const osg::Vec4& color, RenderFrame& frame, 
                       agg::rasterizer& ras, agg::rendering_buffer& buffer)
        {
            unsigned a = (unsigned)(127.0f+(color.a()*255.0f)/2.0f); // scale alpha up
            agg::rgba8 fgColor = agg::rgba8( (unsigned)(color.r()*255.0f), (unsigned)(color.g()*255.0f), (unsigned)(color.b()*255.0f), a );
            
            ConstGeometryIterator gi( geometry );
            while( gi.hasMore() )
            {
                const Geometry* g = gi.next();
    
                for( Geometry::const_iterator p = g->begin(); p != g->end(); p++ )
                {
                    const osg::Vec3d& p0 = *p;
                    double x0 = frame.xf*(p0.x()-frame.xmin);
                    double y0 = frame.yf*(p0.y()-frame.ymin);
    
                    if ( p == g->begin() )
                        ras.move_to_d( x0, y0 );
                    else
                    {
                        ras.line_to_d(x0, y0);
                    }
                }
            }
            agg::renderer<agg::span_abgr32, agg::rgba8> ren(buffer);
            ras.render(ren, fgColor);
    
            ras.reset();
        }
    
        
        void rasterizeCoverage(const Geometry* geometry, float value, RenderFrame& frame, 
                               agg::rasterizer& ras, agg::rendering_buffer& buffer)
        {
            ConstGeometryIterator gi( geometry );
            while( gi.hasMore() )
            {
                const Geometry* g = gi.next();
    
                for( Geometry::const_iterator p = g->begin(); p != g->end(); p++ )
                {
                    const osg::Vec3d& p0 = *p;
                    double x0 = frame.xf*(p0.x()-frame.xmin);
                    double y0 = frame.yf*(p0.y()-frame.ymin);
    
                    if ( p == g->begin() )
                        ras.move_to_d( x0, y0 );
                    else
                        ras.line_to_d( x0, y0 );
                }
            }
            
            agg::renderer<span_coverage32, float32> ren(buffer);
            ras.render(ren, value);
            ras.reset();
        }
    
    
        virtual std::string getExtension()  const 
        {
            return "png";
        }
    
    private:
        const AGGLiteOptions2 _options;
        std::string _configPath;
    };
    
    
    /**
     * Plugin entry point for the AGGLite2 feature rasterizer
     */
    class AGGLiteRasterizerTileSourceDriver2 : public TileSourceDriver
    {
        public:
            AGGLiteRasterizerTileSourceDriver2() {}
    
            virtual const char* className() const
            {
                return "AGG-Lite2 feature rasterizer";
            }
            
            virtual bool acceptsExtension(const std::string& extension) const
            {
                return
                    osgDB::equalCaseInsensitive( extension, "osgearth_agglite2" ) ||
                    osgDB::equalCaseInsensitive( extension, "osgearth_rasterize2" );
            }
    
            virtual ReadResult readObject(const std::string& file_name, const Options* options) const
            {
                std::string ext = osgDB::getFileExtension( file_name );
                if ( !acceptsExtension( ext ) )
                {
                    return ReadResult::FILE_NOT_HANDLED;
                }
    
                return new AGGLiteRasterizerTileSource2( getTileSourceOptions(options) );
            }
    };
    
    REGISTER_OSGPLUGIN(osgearth_agglite2, AGGLiteRasterizerTileSourceDriver2)
  • 相关阅读:
    几何画板表现两集合的差集的教程
    MathType如何编辑大三角形符号
    几何画板如何绘制动态正切函数图像
    MathType如何设置标尺的单位
    模拟按键
    oauth2.0
    PHP CURL POST提交
    Eclipse导入到web项目没有run on server
    实时刷新
    js 实时数据显示
  • 原文地址:https://www.cnblogs.com/coolbear/p/7251442.html
Copyright © 2020-2023  润新知