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

osgEarth2.8加载矢量数据描边效果-LMLPHPosgEarth2.8加载矢量数据描边效果-LMLPHP

测试文件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(, , , );
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()
{
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 << );
float* f = (float*)p;
do
{
unsigned char cover = *covers++;
int hasData = cover > ;
*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 << );
float* f = (float*)p;
do {
*f++ = c.value;
}
while(--count);
} static float32 get(unsigned char* ptr, int x)
{
unsigned char* p = ptr + (x << );
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(), , 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()* ); // 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(,,,));
}
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() << "\n"; // 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() > )
{
// 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()* ); // 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( );
cropPoly->push_back( osg::Vec3d( cropExtent.xMin(), cropExtent.yMin(), ));
cropPoly->push_back( osg::Vec3d( cropExtent.xMax(), cropExtent.yMin(), ));
cropPoly->push_back( osg::Vec3d( cropExtent.xMax(), cropExtent.yMax(), ));
cropPoly->push_back( osg::Vec3d( cropExtent.xMin(), cropExtent.yMax(), )); // 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(,,,);
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() << "\n"; // 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() > )
{
// 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()*; 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() * ); // 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();
cropPoly->push_back(osg::Vec3d(cropExtent.xMin(), cropExtent.yMin(), ));
cropPoly->push_back(osg::Vec3d(cropExtent.xMax(), cropExtent.yMin(), ));
cropPoly->push_back(osg::Vec3d(cropExtent.xMax(), cropExtent.yMax(), ));
cropPoly->push_back(osg::Vec3d(cropExtent.xMin(), cropExtent.yMax(), )); // 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=; i<image->s()*image->t()*; i+=, pixel+=)
{
std::swap( pixel[], pixel[] );
std::swap( pixel[], pixel[] );
}
} 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)
05-11 14:47