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:
parent
2e5f2d7e24
commit
d5b0432dd7
12 changed files with 183 additions and 66 deletions
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 )
|
||||
|
|
15
src/map.cpp
15
src/map.cpp
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue