Created
August 12, 2008 05:18
-
-
Save lwu/5009 to your computer and use it in GitHub Desktop.
example code demonstrating Mapnik C++ API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This code snippet, modifed from Mpanik's rundemo.cpp (r727, license LGPL), | |
renders the State of California using USGS state boundaries data. | |
Here's a play-by-play (via https://lists.berlios.de/pipermail/mapnik-devel/2008-August/000679.html) | |
rundemo.cpp renders a map of Ontario/Quebec, and instead I wanted to draw a | |
map of California and its surrounding states. | |
I grabbed the data from the USGS in the form of "statesp020" (google it, or | |
browse through nationalatlas.gov) and first wanted to modify rundemo.py | |
instead. Alas, this is uncharted territory, as the Python binding does not | |
yet support the mapnik::query object (see the near empty | |
mapnik/bindings/python/mapnik/mapnik_query.cpp). Instead, I modified | |
demo/c++/rundemo.cpp) | |
It took some time to get up to speed on Mapnik internals -- the code is | |
sparsely commented and there doesn't seem to be a canonical Doxygen dump | |
online (although one can be generated manually from the source). The Mapnik | |
wiki has some details, and I started to fill in some small gaps there, but | |
important bits such as what the "res" (second) parameter to the | |
mapnik::query ctor isn't documented anywhere (elsewhere, some feature | |
to_string() method seems to return "TODO"). | |
The basic Mapnik data model which isn't directly documented is something | |
like this. A mapnik Map has Layers, a Layer has a mapnik::datasource_ptr, | |
and a datasource has features. One queries a Map's Layer's datasource by | |
asking it for the features given a mapnik::query, specifying the | |
axis-aligned bounding box (Envelope). | |
Mapnik relies heavily on boost shared_ptr and similar classes, with the | |
convention that _ptr denotes such a pointer. | |
You can follow along here -- http://gist.github.com/5009#LID76 | |
Note the call to (mapnik::query) q.add_property_name('STATE') on Line 80 -- | |
without these, no properties will be returned! Figured this out by reading | |
feature_style_processor.hpp. | |
Line 81 has the feature query call. It would probably be nice to use a | |
filter_featureset<> object instead, but the filter<> objects don't seem to | |
expose public typedefs to facilitate declaring the filter_featureset<> | |
object? | |
So, we asked the Map's Layer's datasource for a featureset_ptr, and then | |
iterate through the linked list of features, checking to see which features | |
pass the previously constructed filter. Unfortunately, the "nil" extent, | |
that is, a default constructed Envelope<double> isn't really a nil extent, | |
but rather an Envelope with negative width and negative height. That's okay | |
but you shouldn't tell such an Envelope to expand_to_include() another | |
Envelope, as it will do the Wrong Thing. | |
I was hoping that it would work the other way, but there may or may not be | |
reasons to design the library this way (code simplicity). | |
Overall, even though the library is as-of-yet sparsely documented, it seems | |
to work pretty well even though my XCode compiles crash whereas gcc compiles | |
don't (ostensibly with the same include, compile, and linking options). The | |
Python binding has some rough edges, and there are cases where appropriate | |
public typedefs (in the "traits" spirit) would make figuring out how to type | |
things somewhat simpler. | |
~L |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***************************************************************************** | |
* Example code modified from Mapnik rundemo.cpp (r727, license LGPL). | |
* Renders the State of California using USGS state boundaries data. | |
*****************************************************************************/ | |
// define before any includes | |
#define BOOST_SPIRIT_THREADSAFE | |
#include <mapnik/map.hpp> | |
#include <mapnik/datasource_cache.hpp> | |
#include <mapnik/font_engine_freetype.hpp> | |
#include <mapnik/agg_renderer.hpp> | |
#include <mapnik/filter_factory.hpp> | |
#include <mapnik/color_factory.hpp> | |
#include <mapnik/image_util.hpp> | |
#include <mapnik/config_error.hpp> | |
#include <iostream> | |
int main ( int argc , char** argv) | |
{ | |
if (argc != 2) | |
{ | |
std::cout << "usage: $0 <mapnik_install_dir>\n"; | |
return EXIT_SUCCESS; | |
} | |
using namespace mapnik; | |
try { | |
std::string mapnik_dir(argv[1]); | |
datasource_cache::instance()->register_datasources(mapnik_dir + "/plugins/input/shape"); | |
freetype_engine::register_font(mapnik_dir + "/fonts/dejavu-ttf-2.14/DejaVuSans.ttf"); | |
Map m(800,600); | |
m.set_background(color_factory::from_string("cadetblue")); | |
// create styles | |
// States (polygon) | |
feature_type_style cali_style; | |
rule_type cali_rule; | |
filter_ptr cali_filter = create_filter("[STATE] = 'California'"); | |
cali_rule.set_filter(cali_filter); | |
cali_rule.append(polygon_symbolizer(Color(250, 190, 183))); | |
cali_style.add_rule(cali_rule); | |
// Provinces (polyline) | |
feature_type_style provlines_style; | |
stroke provlines_stk (Color(0,0,0),1.0); | |
provlines_stk.add_dash(8, 4); | |
provlines_stk.add_dash(2, 2); | |
provlines_stk.add_dash(2, 2); | |
rule_type provlines_rule; | |
provlines_rule.append(polygon_symbolizer(color_factory::from_string("cornsilk"))); | |
provlines_rule.append(line_symbolizer(provlines_stk)); | |
provlines_rule.set_filter(create_filter("[STATE] <> 'California'")); | |
cali_style.add_rule(provlines_rule); | |
m.insert_style("cali",cali_style); | |
// Layers | |
// Provincial polygons | |
{ | |
parameters p; | |
p["type"]="shape"; | |
p["file"]="../data/statesp020"; // State Boundaries of the United States [SHP] | |
Layer lyr("Cali"); | |
lyr.set_datasource(datasource_cache::instance()->create(p)); | |
lyr.add_style("cali"); | |
m.addLayer(lyr); | |
} | |
// Get layer's featureset | |
Layer lay = m.getLayer(0); | |
mapnik::datasource_ptr ds = lay.datasource(); | |
mapnik::query q(lay.envelope(), 1.0 /* what does this "res" param do? */); | |
q.add_property_name("STATE"); // NOTE: Without this call, no properties will be found! | |
mapnik::featureset_ptr fs = ds->features(q); | |
// One day, use filter_featureset<> instead? | |
Envelope<double> extent; // NOTE: nil extent = <[0,0], [-1,-1]> | |
// Loop through features in the set, get extent of those that match query && filter | |
feature_ptr feat = fs->next(); | |
filter_ptr cali_f(create_filter("[STATE] = 'California'")); | |
std::cerr << cali_f->to_string() << std::endl; // NOTE: prints (STATE=TODO)! | |
while (feat) { | |
if (cali_f->pass(*feat)) { | |
for (unsigned i=0; i<feat->num_geometries();++i) { | |
geometry2d & geom = feat->get_geometry(i); | |
if (extent.width() < 0 && extent.height() < 0) { | |
// NOTE: expand_to_include() broken w/ nil extent. Work around. | |
extent = geom.envelope(); | |
} | |
extent.expand_to_include(geom.envelope()); | |
} | |
} | |
feat = fs->next(); | |
} | |
m.zoomToBox(extent); | |
m.zoom(1.2); // zoom out slightly | |
Image32 buf(m.getWidth(),m.getHeight()); | |
agg_renderer<Image32> ren(m,buf); | |
ren.apply(); | |
save_to_file<ImageData32>(buf.data(),"cali.png","png"); | |
} | |
catch ( const mapnik::config_error & ex ) | |
{ | |
std::cerr << "### Configuration error: " << ex.what(); | |
return EXIT_FAILURE; | |
} | |
catch ( const std::exception & ex ) | |
{ | |
std::cerr << "### std::exception: " << ex.what(); | |
return EXIT_FAILURE; | |
} | |
catch ( ... ) | |
{ | |
std::cerr << "### Unknown exception." << std::endl; | |
return EXIT_FAILURE; | |
} | |
return EXIT_SUCCESS; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
g++ -g -I/usr/local/include/mapnik -I/opt/local/include -I/opt/local/include/freetype2 -I../../agg/include -L/usr/local/lib -L/opt/local/lib -lmapnik -lboost_thread-mt -licuuc cali.cpp -o cali |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment