Many metawriter improvements:

- Easier to configure
- Correct JSON output
- Handling more than one renderer run (writing pre-/postamble is no longer done in constructor/destructor)
- Collect all attributes required by metawriters
This commit is contained in:
Hermann Kraus 2010-07-12 15:27:33 +00:00
parent 2e5f2d7e24
commit d5b0432dd7
12 changed files with 183 additions and 66 deletions

View file

@ -106,7 +106,7 @@ struct symbolizer_attributes : public boost::static_visitor<>
expression_attributes f_attr(names_);
boost::apply_visitor(f_attr,*orientation_expr);
}
collect_metawriter(sym);
}
void operator () (point_symbolizer const& sym)
@ -116,6 +116,8 @@ struct symbolizer_attributes : public boost::static_visitor<>
{
path_processor_type::collect_attributes(*filename_expr,names_);
}
collect_metawriter(sym);
}
void operator () (line_pattern_symbolizer const& sym)
@ -125,6 +127,7 @@ struct symbolizer_attributes : public boost::static_visitor<>
{
path_processor_type::collect_attributes(*filename_expr,names_);
}
collect_metawriter(sym);
}
void operator () (polygon_pattern_symbolizer const& sym)
@ -134,6 +137,7 @@ struct symbolizer_attributes : public boost::static_visitor<>
{
path_processor_type::collect_attributes(*filename_expr,names_);
}
collect_metawriter(sym);
}
void operator () (shield_symbolizer const& sym)
@ -150,6 +154,7 @@ struct symbolizer_attributes : public boost::static_visitor<>
{
path_processor_type::collect_attributes(*filename_expr,names_);
}
collect_metawriter(sym);
}
void operator () (glyph_symbolizer const& sym)
@ -188,12 +193,17 @@ struct symbolizer_attributes : public boost::static_visitor<>
expression_attributes f_attr(names_);
boost::apply_visitor(f_attr,*color_expr);
}
collect_metawriter(sym);
}
// TODO - support remaining syms
private:
std::set<std::string>& names_;
void collect_metawriter(symbolizer_base const& sym)
{
metawriter_properties const& properties = sym.get_metawriter_properties();
names_.insert(properties.begin(), properties.end());
}
};

View file

@ -84,6 +84,13 @@ public:
#endif
Processor & p = static_cast<Processor&>(*this);
p.start_map_processing(m_);
Map::const_metawriter_iterator metaItr = m_.begin_metawriters();
Map::const_metawriter_iterator metaItrEnd = m_.end_metawriters();
for (;metaItr!=metaItrEnd; ++metaItr)
{
metaItr->second->start();
}
try
{
@ -109,7 +116,13 @@ public:
{
std::clog << "proj_init_error:" << ex.what() << "\n";
}
metaItr = m_.begin_metawriters();
for (;metaItr!=metaItrEnd; ++metaItr)
{
metaItr->second->stop();
}
p.end_map_processing(m_);
}
private:

View file

@ -87,6 +87,7 @@ public:
typedef std::map<std::string,feature_type_style>::iterator style_iterator;
typedef std::map<std::string,font_set>::const_iterator const_fontset_iterator;
typedef std::map<std::string,font_set>::iterator fontset_iterator;
typedef std::map<std::string,metawriter_ptr>::const_iterator const_metawriter_iterator;
/*! \brief Default constructor.
*
@ -166,7 +167,7 @@ public:
*/
boost::optional<feature_type_style const&> find_style(std::string const& name) const;
/*! \brief Insert a meta-writer in the map.
/*! \brief Insert a metawriter in the map.
* @param name The name of the writer.
* @param style A pointer to the writer to insert.
* @return true If success.
@ -174,16 +175,31 @@ public:
*/
bool insert_metawriter(std::string const& name, metawriter_ptr const& writer);
/*! \brief Remove a meta-writer from the map.
/*! \brief Remove a metawriter from the map.
* @param name The name of the writer.
*/
void remove_metawriter(const std::string& name);
/*! \brief Find a meta-writer.
/*! \brief Find a metawriter.
* @param name The name of the writer.
* @return The writer if found. If not found return 0.
*/
metawriter_ptr find_metawriter(std::string const& name) const;
/*! \brief Get all metawriters.
* @return Const reference to metawriters.
*/
std::map<std::string,metawriter_ptr> const& metawriters() const;
/*! \brief Get first iterator in metawriters.
* @return Constant metawriter iterator.
*/
const_metawriter_iterator begin_metawriters() const;
/*! \brief Get last iterator in metawriters.
* @return Constant metawriter iterator.
*/
const_metawriter_iterator end_metawriters() const;
/*! \brief Insert a fontset into the map.
* @param name The name of the fontset.

View file

@ -27,24 +27,48 @@
// Mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/filter_factory.hpp>
// Boost
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
// STL
#include <set>
#include <string>
namespace mapnik {
/** All properties to be output by a metawriter. */
typedef std::set<std::string> metawriter_properties;
/** Abstract baseclass for all metawriter classes. */
class metawriter
{
public:
metawriter(metawriter_properties dflt_properties) : dflt_properties_(dflt_properties) {}
virtual ~metawriter() {};
virtual void add_box(box2d<double> box, Feature const &feature, proj_transform const& prj_trans, CoordTransform const &t, expression_ptr expression)=0;
/** Output a rectangular area.
* \param box Area (in pixel coordinates)
* \param feature The feature being processed
* \param prj_trans Projection transformation
* \param t Cooridnate transformation
* \param properties List of properties to output
*/
virtual void add_box(box2d<double> box, Feature const &feature,
proj_transform const& prj_trans,
CoordTransform const &t,
metawriter_properties const& properties = metawriter_properties())=0;
virtual void start() {};
virtual void stop() {};
static metawriter_properties parse_properties(boost::optional<std::string> str);
protected:
metawriter_properties dflt_properties_;
};
typedef boost::shared_ptr<metawriter> metawriter_ptr;
typedef std::pair<metawriter_ptr, metawriter_properties> metawriter_with_properties;
};

View file

@ -35,12 +35,17 @@ namespace mapnik {
class metawriter_json : public metawriter, private boost::noncopyable
{
public:
metawriter_json(std::string fn, expression_ptr dflt_expr=expression_ptr());
metawriter_json(metawriter_properties dflt_properties, std::string fn);
~metawriter_json();
virtual void add_box(box2d<double> box, Feature const &feature, proj_transform const& prj_trans, CoordTransform const &t, expression_ptr expression);
virtual void add_box(box2d<double> box, Feature const &feature,
proj_transform const& prj_trans,
CoordTransform const& t,
metawriter_properties const& properties);
virtual void start();
virtual void stop();
private:
std::fstream f;
expression_ptr dflt_expr_;
std::string fn_;
int count;
};

View file

@ -27,7 +27,6 @@
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/metawriter.hpp>
// boost
@ -44,7 +43,7 @@ class MAPNIK_DECL symbolizer_base {
*
* expression can be empty the default expression of
* the writer is used in this case. */
void add_metawriter(std::string name, expression_ptr expression);
void add_metawriter(std::string name, metawriter_properties const& properties);
/** Cache metawriter objects to avoid repeated lookups while processing.
*
* This function has to be called before the symbolizer is used, because
@ -56,9 +55,13 @@ class MAPNIK_DECL symbolizer_base {
*
* This functions requires that cache_metawriters() was called first.
*/
std::pair<metawriter_ptr, expression_ptr> get_metawriter() const;
metawriter_with_properties get_metawriter() const;
/** Get properties needed for metawriter.
* \note This function is a helperfunction for class attribute_collector.
*/
metawriter_properties const& get_metawriter_properties() const { return properties_;}
private:
expression_ptr expression_;
metawriter_properties properties_;
std::string writer_name_;
metawriter_ptr writer_ptr_;
};

View file

@ -114,7 +114,7 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
{
svg_renderer.render(*ras_ptr, sl, ren, tr, renb.clip_box(), sym.get_opacity());
detector_.insert(extent);
std::pair<metawriter_ptr, expression_ptr> writer = sym.get_metawriter();
metawriter_with_properties writer = sym.get_metawriter();
if (writer.first)
{
writer.first->add_box(extent, feature, prj_trans, t_, writer.second);
@ -155,7 +155,7 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
{
pixmap_.set_rectangle_alpha2(*(*data), px, py, sym.get_opacity());
detector_.insert(label_ext);
std::pair<metawriter_ptr, expression_ptr> writer = sym.get_metawriter();
metawriter_with_properties writer = sym.get_metawriter();
if (writer.first)
{
writer.first->add_box(label_ext, feature, prj_trans, t_, writer.second);

View file

@ -777,7 +777,7 @@ void cairo_renderer_base::process(point_symbolizer const& sym,
context.add_image(px, py, *(*data), sym.get_opacity());
detector_.insert(label_ext);
std::pair<metawriter_ptr, expression_ptr> writer = sym.get_metawriter();
metawriter_with_properties writer = sym.get_metawriter();
if (writer.first)
{
writer.first->add_box(label_ext, feature, prj_trans, t_, writer.second);

View file

@ -336,10 +336,9 @@ void map_parser::parse_style( Map & map, ptree const & sty )
} catch (const config_error & ex) {
if ( ! name.empty() ) {
ex.append_context(string("in style '") + name + "' in map '" + filename_ + "'");
} else {
ex.append_context(string("in map '") + filename_ + "'");
ex.append_context(string("in style '") + name + "'");
}
ex.append_context(string("in map '") + filename_ + "'");
throw;
}
}
@ -354,17 +353,16 @@ void map_parser::parse_metawriter(Map & map, ptree const & pt)
string type = get_attr<string>(pt, "type");
if (type == "json") {
string file = get_attr<string>(pt, "file");
writer = metawriter_ptr(new metawriter_json(file));
writer = metawriter_ptr(new metawriter_json(metawriter_properties(/*TODO*/), file));
} else {
throw config_error(string("Unknown type '") + type + "'");
}
map.insert_metawriter(name, writer);
} catch (const config_error & ex) {
if (!name.empty()) {
ex.append_context(string("in meta writer '") + name + "' in map '" + filename_ + "'");
} else {
ex.append_context(string("in map '") + filename_ + "'");
ex.append_context(string("in meta writer '") + name + "'");
}
ex.append_context(string("in map '") + filename_ + "'");
throw;
}
}
@ -403,8 +401,9 @@ void map_parser::parse_fontset( Map & map, ptree const & fset )
fontsets_.insert(pair<std::string, font_set>(name, fontset));
} catch (const config_error & ex) {
if ( ! name.empty() ) {
ex.append_context(string("in FontSet '") + name + "' in map '" + filename_ + "')");
ex.append_context(string("in FontSet '") + name + "'");
}
ex.append_context(string("in map '") + filename_ + "'");
throw;
}
}
@ -705,12 +704,7 @@ void map_parser::parse_metawriter_in_symbolizer(symbolizer_base &sym, ptree cons
optional<std::string> writer = get_opt_attr<string>(pt, "meta-writer");
if (!writer) return;
optional<std::string> output = get_opt_attr<string>(pt, "meta-output");
expression_ptr expression;
if (output) {
expression = parse_expression(*output, "utf8");
}
clog << "adding metawriter " << *writer << "\n";
sym.add_metawriter(*writer, expression);
sym.add_metawriter(*writer, metawriter::parse_properties(output));
}
void map_parser::parse_point_symbolizer( rule_type & rule, ptree const & sym )

View file

@ -169,6 +169,21 @@ metawriter_ptr Map::find_metawriter(std::string const& name) const
return metawriter_ptr();
}
std::map<std::string,metawriter_ptr> const& Map::metawriters() const
{
return metawriters_;
}
Map::const_metawriter_iterator Map::begin_metawriters() const
{
return metawriters_.begin();
}
Map::const_metawriter_iterator Map::end_metawriters() const
{
return metawriters_.end();
}
bool Map::insert_fontset(std::string const& name, font_set const& fontset)
{
return fontsets_.insert(make_pair(name, fontset)).second;

View file

@ -24,43 +24,66 @@
// Mapnik
#include <mapnik/metawriter.hpp>
#include <mapnik/metawriter_json.hpp>
#include <mapnik/expression_evaluator.hpp>
// Boost
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
// STL
#include <iomanip>
#include <cstdio>
namespace mapnik {
metawriter_json::metawriter_json(std::string fn, expression_ptr dflt_expr) : dflt_expr_(dflt_expr), count(0)
metawriter_json::metawriter_json(metawriter_properties dflt_properties, std::string fn)
: metawriter(dflt_properties), fn_(fn), count(0)
{
f.open(fn.c_str(), std::fstream::out | std::fstream::trunc);
if (f.fail()) perror((std::string("Failed to open file ") + fn).c_str());
f << "{ \"type\": \"FeatureCollection\", \"features\": [\n";
}
metawriter_json::~metawriter_json()
{
if (f.is_open()) {
stop();
}
void metawriter_json::start()
{
if (f.is_open())
{
std::cerr << "ERROR: GeoJSON metawriter is already active!\n";
}
f.open(fn_.c_str(), std::fstream::out | std::fstream::trunc);
if (f.fail()) perror((std::string("Failed to open file ") + fn_).c_str());
f << "{ \"type\": \"FeatureCollection\", \"features\": [\n";
}
void metawriter_json::stop()
{
if (f.is_open())
{
f << " ] }\n";
f.close();
}
std::clog << "Destroying metawriter\n";
}
void metawriter_json::add_box(box2d<double> box, Feature const &feature, proj_transform const& prj_trans, CoordTransform const &t, expression_ptr expression)
void metawriter_json::add_box(box2d<double> box, Feature const &feature,
proj_transform const& prj_trans, CoordTransform const &t,
const metawriter_properties& properties)
{
expression_ptr e;
if (expression) {
e = expression;
} else {
e = dflt_expr_;
metawriter_properties props;
if (properties.empty())
{
props = dflt_properties_;
}
if (!e) {
std::clog << "WARNING: No expression available for JSON metawriter.\n";
else
{
props = properties;
}
if (props.empty())
{
std::cerr << "WARNING: No expression available for GeoJSON metawriter.\n";
return;
}
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature),*e);
UnicodeString text = result.to_unicode();
/* Coordinate transform in renderer:
input: layer srs
@ -86,15 +109,38 @@ void metawriter_json::add_box(box2d<double> box, Feature const &feature, proj_tr
double maxx = box.maxx();
double maxy = box.maxy();
if (count++) {
f << ",\n";
}
if (count++) f << ",\n";
f << std::fixed << std::setprecision(8) << "{ \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Polygon\",\n \"coordinates\": [ [ [" <<
minx << ", " << miny << "], [" <<
maxx << ", " << miny << "], [" <<
maxx << ", " << maxy << "], [" <<
minx << ", " << maxy << "] ] ] }," <<
"\n \"properties\": {" << text << "} }";
"\n \"properties\": {";
std::map<std::string, value> fprops = feature.props();
int i = 0;
BOOST_FOREACH(std::string p, props)
{
std::map<std::string, value>::const_iterator itr = fprops.find(p);
std::string text;
if (itr != fprops.end())
{
//Property found
text = boost::replace_all_copy(boost::replace_all_copy(itr->second.to_string(), "\\", "\\\\"), "\"", "\\\"");
}
if (i++) f << ",";
f << "\n \"" << p << "\":\"" << text << "\"";
}
f << "\n} }";
}
metawriter_properties metawriter::parse_properties(boost::optional<std::string> str)
{
metawriter_properties properties;
if (str) {
std::string str_ = boost::algorithm::erase_all_copy(*str, " ");
boost::split(properties, str_, boost::is_any_of(","), boost::token_compress_on);
}
return properties;
}
};

View file

@ -27,29 +27,20 @@
namespace mapnik {
void symbolizer_base::add_metawriter(std::string name, expression_ptr expression)
void symbolizer_base::add_metawriter(std::string name, metawriter_properties const& properties)
{
expression_ = expression;
properties_ = properties;
writer_name_ = name;
#ifdef MAPNIK_DEBUG
std::clog << "adding metawriter" << name << "\n";
#endif
}
void symbolizer_base::cache_metawriters(Map const &m)
{
#ifdef MAPNIK_DEBUG
std::clog << "Caching metawriters\n";
#endif
writer_ptr_ = m.find_metawriter(writer_name_);
#ifdef MAPNIK_DEBUG
std::clog << writer_ptr_ << "name:" << writer_name_ << "\n";
#endif
}
std::pair<metawriter_ptr, expression_ptr> symbolizer_base::get_metawriter() const
metawriter_with_properties symbolizer_base::get_metawriter() const
{
return std::pair<metawriter_ptr, expression_ptr>(writer_ptr_, expression_);
return metawriter_with_properties(writer_ptr_, properties_);
}
symbolizer_with_image::symbolizer_with_image(path_expression_ptr file)