Metawriter support for TextSymbolizer.

This commit is contained in:
Hermann Kraus 2010-08-10 12:19:19 +00:00
parent 85cd4b67c3
commit 30470bd52b
5 changed files with 164 additions and 53 deletions

View file

@ -27,6 +27,7 @@
// Mapnik // Mapnik
#include <mapnik/box2d.hpp> #include <mapnik/box2d.hpp>
#include <mapnik/feature.hpp> #include <mapnik/feature.hpp>
#include <mapnik/font_engine_freetype.hpp>
// Boost // Boost
#include <boost/utility.hpp> #include <boost/utility.hpp>
@ -81,6 +82,12 @@ class metawriter
virtual void add_box(box2d<double> const& box, Feature const& feature, virtual void add_box(box2d<double> const& box, Feature const& feature,
CoordTransform const& t, CoordTransform const& t,
metawriter_properties const& properties = metawriter_properties())=0; metawriter_properties const& properties = metawriter_properties())=0;
virtual void add_text(placement const& placement,
face_set_ptr face,
Feature const& feature,
CoordTransform const& t,
metawriter_properties const& properties = metawriter_properties())=0;
/** Start processing. /** Start processing.
* Write file header, init database connection, ... * Write file header, init database connection, ...
* *

View file

@ -43,6 +43,11 @@ public:
virtual void add_box(box2d<double> const& box, Feature const& feature, virtual void add_box(box2d<double> const& box, Feature const& feature,
CoordTransform const& t, CoordTransform const& t,
metawriter_properties const& properties); metawriter_properties const& properties);
virtual void add_text(placement const& p,
face_set_ptr face,
Feature const& feature,
CoordTransform const& t,
metawriter_properties const& properties = metawriter_properties());
virtual void start(metawriter_property_map const& properties); virtual void start(metawriter_property_map const& properties);
virtual void stop(); virtual void stop();
@ -56,6 +61,11 @@ public:
bool get_only_nonempty() { return only_nonempty_; } bool get_only_nonempty() { return only_nonempty_; }
virtual void set_map_srs(projection const& proj); virtual void set_map_srs(projection const& proj);
protected: protected:
enum {
HEADER_NOT_WRITTEN = -1,
STOPPED = -2,
STARTED = 0,
};
/** Features written. */ /** Features written. */
int count_; int count_;
bool only_nonempty_; bool only_nonempty_;
@ -63,6 +73,29 @@ protected:
proj_transform *trans_; proj_transform *trans_;
projection output_srs_; projection output_srs_;
virtual void write_header(); virtual void write_header();
inline void write_feature_header(std::string type) {
if (count_ == HEADER_NOT_WRITTEN) write_header();
if (count_++) *f_ << ",\n";
#ifdef MAPNIK_DEBUG
if (count_ == STOPPED)
{
std::cerr << "WARNING: Metawriter not started before using it.\n";
}
#endif
*f_ << "{ \"type\": \"Feature\",\n \"geometry\": { \"type\": \""<<type<<"\",\n \"coordinates\":";
}
void write_properties(Feature const& feature, metawriter_properties const& properties);
inline void write_point(CoordTransform const& t, double x, double y, bool last = false)
{
double z = 0.0;
t.backward(&x, &y);
trans_->forward(x, y, z);
*f_ << "["<<x<<","<<y<<"]";
if (!last) {
*f_ << ",";
}
}
private: private:
std::ostream *f_; std::ostream *f_;
}; };

View file

@ -121,6 +121,7 @@ void agg_renderer<T>::process(text_symbolizer const& sym,
finder.find_line_placements<path_type>(text_placement,path); finder.find_line_placements<path_type>(text_placement,path);
} }
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii) for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii)
{ {
double x = text_placement.placements[ii].starting_x; double x = text_placement.placements[ii].starting_x;
@ -128,6 +129,9 @@ void agg_renderer<T>::process(text_symbolizer const& sym,
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]); box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
ren.render(x,y); ren.render(x,y);
} }
metawriter_with_properties writer = sym.get_metawriter();
if (writer.first) writer.first->add_text(text_placement, faces, feature, t_, writer.second);
} }
} }
} }

View file

@ -23,6 +23,7 @@
// Mapnik // Mapnik
#include <mapnik/metawriter.hpp> #include <mapnik/metawriter.hpp>
#include <mapnik/metawriter_json.hpp> #include <mapnik/metawriter_json.hpp>
#include <mapnik/placement_finder.hpp>
// Boost // Boost
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -32,10 +33,6 @@
#include <iomanip> #include <iomanip>
#include <cstdio> #include <cstdio>
#define HEADER_NOT_WRITTEN -1
#define STOPPED -2
#define STARTED 0
namespace mapnik { namespace mapnik {
UnicodeString const& metawriter_property_map::operator[](std::string const& key) const UnicodeString const& metawriter_property_map::operator[](std::string const& key) const
@ -68,7 +65,7 @@ void metawriter_json_stream::start(metawriter_property_map const& properties)
void metawriter_json_stream::write_header() void metawriter_json_stream::write_header()
{ {
assert(f_); assert(f_);
*f_ << "{ \"type\": \"FeatureCollection\", \"features\": [\n"; *f_ << "{ \"type\": \"FeatureCollection\", \"features\": [\n" << std::fixed << std::setprecision(8);
count_ = STARTED; count_ = STARTED;
} }
@ -98,50 +95,9 @@ metawriter_json_stream::metawriter_json_stream(metawriter_properties dflt_proper
{ {
} }
void metawriter_json_stream::write_properties(Feature const& feature, metawriter_properties const& properties)
void metawriter_json_stream::add_box(box2d<double> const &box, Feature const& feature,
CoordTransform const& t, metawriter_properties const& properties)
{ {
/* Check if feature is in bounds. */ *f_ << "}," << //Close coordinates object
if (box.maxx() < 0 || box.maxy() < 0 || box.minx() > width_ || box.miny() > height_) return;
if (count_ == HEADER_NOT_WRITTEN) write_header();
#ifdef MAPNIK_DEBUG
if (count_ == STOPPED)
{
std::cerr << "WARNING: Metawriter not started before using it.\n";
}
#endif
/* Coordinate transform in renderer:
input: layer srs
prj_trans.backwards() [prj_trans: map -> layer]
intermediate: map srs
t_.forward()
output: pixels
Our transform:
input: pixels
t_.backward()
intermediate: map srs
trans_.forward()
output: WGS84
*/
//t_ coord transform has transform for box2d combined with proj_transform
box2d<double> transformed = t.backward(box, *trans_);
double minx = transformed.minx();
double miny = transformed.miny();
double maxx = transformed.maxx();
double maxy = transformed.maxy();
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\": {"; "\n \"properties\": {";
std::map<std::string, value> fprops = feature.props(); std::map<std::string, value> fprops = feature.props();
int i = 0; int i = 0;
@ -161,6 +117,113 @@ void metawriter_json_stream::add_box(box2d<double> const &box, Feature const& fe
*f_ << "\n} }"; *f_ << "\n} }";
} }
/* Coordinate transform in renderer:
input: layer srs
prj_trans.backwards() [prj_trans: map -> layer]
intermediate: map srs
t_.forward()
output: pixels
Our transform:
input: pixels
t_.backward()
intermediate: map srs
trans_.forward()
output: WGS84
*/
void metawriter_json_stream::add_box(box2d<double> const &box, Feature const& feature,
CoordTransform const& t, metawriter_properties const& properties)
{
/* Check if feature is in bounds. */
if (box.maxx() < 0 || box.maxy() < 0 || box.minx() > width_ || box.miny() > height_) return;
//t_ coord transform has transform for box2d combined with proj_transform
box2d<double> transformed = t.backward(box, *trans_);
double minx = transformed.minx();
double miny = transformed.miny();
double maxx = transformed.maxx();
double maxy = transformed.maxy();
write_feature_header("Polygon");
*f_ << " [ [ [" <<
minx << ", " << miny << "], [" <<
maxx << ", " << miny << "], [" <<
maxx << ", " << maxy << "], [" <<
minx << ", " << maxy << "] ] ]";
write_properties(feature, properties);
}
//TODO: Remove this
inline void combined_backward(double &x, double &y, CoordTransform const& t, proj_transform const* trans_)
{
double z = 0.0;
t.backward(&x, &y);
trans_->forward(x, y, z);
}
void metawriter_json_stream::add_text(placement const& p,
face_set_ptr face,
Feature const& feature,
CoordTransform const& t,
metawriter_properties const& properties)
{
for (unsigned n = 0; n < p.placements.size(); n++) {
placement_element & current_placement = const_cast<placement_element &>(p.placements[n]);
bool inside = false;
for (int i = 0; i < current_placement.num_nodes(); ++i) {
current_placement.rewind();
int c; double x, y, angle;
current_placement.vertex(&c, &x, &y, &angle);
if (x > 0 && x < width_ && y > 0 && y < height_) {
inside = true;
break;
}
}
if (!inside) continue;
write_feature_header("MultiPolygon");
*f_ << "[";
for (int i = 0; i < current_placement.num_nodes(); ++i) {
if (i) {
*f_ << ",";
}
int c; double x, y, angle;
current_placement.vertex(&c, &x, &y, &angle);
font_face_set::dimension_t ci = face->character_dimensions(c);
//TODO: Optimize for angle == 0
double sina = sin(angle);
double cosa = cos(angle);
double x0 = current_placement.starting_x + x - sina*ci.ymin;
double y0 = current_placement.starting_y - y - cosa*ci.ymin;
double x1 = x0 + ci.width * cosa;
double y1 = y0 - ci.width * sina;
double x2 = x0 + (ci.width * cosa - ci.height * sina);
double y2 = y0 - (ci.width * sina + ci.height * cosa);
double x3 = x0 - ci.height * sina;
double y3 = y0 - ci.height * cosa;
*f_ << "\n [[";
write_point(t, x0, y0);
write_point(t, x1, y1);
write_point(t, x2, y2);
write_point(t, x3, y3, true);
*f_ << "]]";
}
*f_ << "]";
write_properties(feature, properties);
}
}
void metawriter_json_stream::set_map_srs(projection const& input_srs_) void metawriter_json_stream::set_map_srs(projection const& input_srs_)
{ {
if (trans_) delete trans_; if (trans_) delete trans_;

View file

@ -83,7 +83,8 @@ IMPLEMENT_ENUM( text_convert_e, text_convert_strings );
text_symbolizer::text_symbolizer(expression_ptr name, std::string const& face_name, unsigned size, color const& fill) text_symbolizer::text_symbolizer(expression_ptr name, std::string const& face_name, unsigned size, color const& fill)
: name_(name), : symbolizer_base(),
name_(name),
face_name_(face_name), face_name_(face_name),
//fontset_(default_fontset), //fontset_(default_fontset),
size_(size), size_(size),
@ -113,7 +114,8 @@ text_symbolizer::text_symbolizer(expression_ptr name, std::string const& face_na
jalign_(J_MIDDLE) {} jalign_(J_MIDDLE) {}
text_symbolizer::text_symbolizer(expression_ptr name, unsigned size, color const& fill) text_symbolizer::text_symbolizer(expression_ptr name, unsigned size, color const& fill)
: name_(name), : symbolizer_base(),
name_(name),
//face_name_(""), //face_name_(""),
//fontset_(default_fontset), //fontset_(default_fontset),
size_(size), size_(size),
@ -143,7 +145,8 @@ text_symbolizer::text_symbolizer(expression_ptr name, unsigned size, color const
jalign_(J_MIDDLE) {} jalign_(J_MIDDLE) {}
text_symbolizer::text_symbolizer(text_symbolizer const& rhs) text_symbolizer::text_symbolizer(text_symbolizer const& rhs)
: name_(rhs.name_), : symbolizer_base(rhs),
name_(rhs.name_),
orientation_(rhs.orientation_), orientation_(rhs.orientation_),
face_name_(rhs.face_name_), face_name_(rhs.face_name_),
fontset_(rhs.fontset_), fontset_(rhs.fontset_),
@ -206,6 +209,7 @@ text_symbolizer& text_symbolizer::operator=(text_symbolizer const& other)
wrap_before_ = other.wrap_before_; wrap_before_ = other.wrap_before_;
halign_ = other.halign_; halign_ = other.halign_;
jalign_ = other.jalign_; jalign_ = other.jalign_;
std::cout << "TODO: Metawriter (text_symbolizer::operator=)\n";
return *this; return *this;
} }