Skip to content

Commit

Permalink
add additional support for dynamically drawing ellipses in the marker…
Browse files Browse the repository at this point in the history
…s_symbolizer, now supporting both line/point placement, metawriters for point placement, and width/height/stroke attributes - TODO - reflect in python bindings, buggy matrix transform for ellipses

git-svn-id: svn+ssh://svn.mapnik.org/trunk@2158 d397654b-2ff0-0310-9e29-ba003691a0f9
  • Loading branch information
dane committed Aug 19, 2010
1 parent c683e0e commit 0cf85f9
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 36 deletions.
42 changes: 39 additions & 3 deletions include/mapnik/markers_symbolizer.hpp
Expand Up @@ -29,9 +29,28 @@
#include <mapnik/symbolizer.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/color.hpp>
#include <mapnik/stroke.hpp>
#include <mapnik/enumeration.hpp>

namespace mapnik {


// TODO - consider merging with text_symbolizer label_placment_e
enum marker_placement_enum {
MARKER_POINT_PLACEMENT,
MARKER_LINE_PLACEMENT,
marker_placement_enum_MAX
};

DEFINE_ENUM( marker_placement_e, marker_placement_enum );

enum marker_type_enum {
ARROW,
ELLIPSE,
marker_type_enum_MAX
};

DEFINE_ENUM( marker_type_e, marker_type_enum );

struct MAPNIK_DECL markers_symbolizer :
public symbolizer_with_image, public symbolizer_base
{
Expand All @@ -42,16 +61,33 @@ struct MAPNIK_DECL markers_symbolizer :
void set_allow_overlap(bool overlap);
bool get_allow_overlap() const;
void set_spacing(double spacing);
float get_spacing() const;
double get_spacing() const;
void set_max_error(double max_error);
float get_max_error() const;
double get_max_error() const;
void set_fill(color fill);
color const& get_fill() const;
void set_width(double width);
double get_width() const;
void set_height(double height);
double get_height() const;
stroke const& get_stroke() const;
void set_stroke(stroke const& stroke);
void set_marker_placement(marker_placement_e marker_p);
marker_placement_e get_marker_placement() const;
void set_marker_type(marker_type_e marker_p);
marker_type_e get_marker_type() const;

private:
bool allow_overlap_;
color fill_;
double spacing_;
double max_error_;
double width_;
double height_;
stroke stroke_;
marker_placement_e marker_p_;
marker_type_e marker_type_;

};

}
Expand Down
178 changes: 152 additions & 26 deletions src/agg/process_markers_symbolizer.cpp
Expand Up @@ -36,6 +36,11 @@
#include "agg_pixfmt_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
#include "agg_scanline_p.h"
#include "agg_path_storage.h"
#include "agg_ellipse.h"
#include "agg_conv_stroke.h"


namespace mapnik {

Expand All @@ -52,6 +57,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
ras_ptr->reset();
ras_ptr->gamma(agg::gamma_linear());
agg::scanline_u8 sl;
agg::scanline_p8 sl_line;
agg::rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_ * 4);
pixfmt pixf(buf);
renderer_base renb(pixf);
Expand All @@ -61,6 +67,9 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
tr.load_from(&m[0]);
tr = agg::trans_affine_scaling(scale_factor_) * tr;
std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);
marker_placement_e placement_method = sym.get_marker_placement();
marker_type_e marker_type = sym.get_marker_type();
metawriter_with_properties writer = sym.get_metawriter();

if (!filename.empty())
{
Expand All @@ -84,7 +93,11 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
for (unsigned i=0; i<feature.num_geometries(); ++i)
{
geometry2d const& geom = feature.get_geometry(i);
if (geom.num_points() <= 1) continue;
if (geom.num_points() <= 1)
{
std::clog << "### Warning svg markers not supported yet for points within markers_symbolizer\n";
continue;
}

path_type path(t_,geom,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
Expand All @@ -97,48 +110,161 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
{
agg::trans_affine matrix = tr *agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y);
svg_renderer.render(*ras_ptr, sl, ren, matrix, renb.clip_box(), sym.get_opacity());
if (writer.first)
//writer.first->add_box(label_ext, feature, t_, writer.second);
std::clog << "### Warning metawriter not yet supported for LINE placement\n";
}
}
}
}
else // FIXME: should default marker be stored in marker_cache ???
{
arrow arrow_;
color const& fill_ = sym.get_fill();
unsigned r = fill_.red();
unsigned g = fill_.green();
unsigned b = fill_.blue();
unsigned a = fill_.alpha();
stroke const& stroke_ = sym.get_stroke();
color const& col = stroke_.get_color();
double strk_width = stroke_.get_width();
unsigned s_r=col.red();
unsigned s_g=col.green();
unsigned s_b=col.blue();
unsigned s_a=col.alpha();
double w = sym.get_width();
double h = sym.get_height();

arrow arrow_;
box2d<double> extent;

double dx = w + (2*strk_width);
double dy = h + (2*strk_width);

if (marker_type == ARROW)
{
extent = arrow_.extent();
double x1 = extent.minx();
double y1 = extent.miny();
double x2 = extent.maxx();
double y2 = extent.maxy();
tr.transform(&x1,&y1);
tr.transform(&x2,&y2);
extent.init(x1,y1,x2,y2);
//std::clog << x1 << " " << y1 << " " << x2 << " " << y2 << "\n";
}
else
{
double x1 = -1 *(dx);
double y1 = -1 *(dy);
double x2 = dx;
double y2 = dy;
tr.transform(&x1,&y1);
tr.transform(&x2,&y2);
extent.init(x1,y1,x2,y2);
//std::clog << x1 << " " << y1 << " " << x2 << " " << y2 << "\n";
}


box2d<double> extent = arrow_.extent();
double x1 = extent.minx();
double y1 = extent.miny();
double x2 = extent.maxx();
double y2 = extent.maxy();
tr.transform(&x1,&y1);
tr.transform(&x2,&y2);
extent.init(x1,y1,x2,y2);

double x;
double y;
double z=0;

agg::path_storage marker;

for (unsigned i=0; i<feature.num_geometries(); ++i)
{
geometry2d const& geom = feature.get_geometry(i);
if (geom.num_points() <= 1) continue;

path_type path(t_,geom,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
sym.get_spacing() * scale_factor_,
sym.get_max_error(),
sym.get_allow_overlap());
double x, y, angle;

while (placement.get_point(&x, &y, &angle))
//if (geom.num_points() <= 1) continue;
if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1)
{
agg::trans_affine matrix = tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y);
agg::conv_transform<arrow, agg::trans_affine> trans(arrow_, matrix);
ras_ptr->add_path(trans);
ren.color(agg::rgba8(r, g, b, a));
agg::render_scanlines(*ras_ptr, sl, ren);
geom.label_position(&x,&y);
prj_trans.backward(x,y,z);
t_.forward(&x,&y);
int px = int(floor(x - 0.5 * dx));
int py = int(floor(y - 0.5 * dy));
box2d<double> label_ext (px, py, px + dx +1, py + dy +1);

if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
{
agg::ellipse c(x, y, w, h);
marker.concat_path(c);
ras_ptr->add_path(marker);
ren.color(agg::rgba8(r, g, b, int(a*sym.get_opacity())));
// TODO - fill with packed scanlines? agg::scanline_p8
// and agg::renderer_outline_aa
agg::render_scanlines(*ras_ptr, sl, ren);

// outline
ras_ptr->reset();
agg::conv_stroke<agg::path_storage> outline(marker);
outline.generator().width(strk_width * scale_factor_);
ras_ptr->add_path(outline);

ren.color(agg::rgba8(s_r, s_g, s_b, int(s_a*stroke_.get_opacity())));
agg::render_scanlines(*ras_ptr, sl_line, ren);

detector_.insert(label_ext);
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
}
}
else
{

if (marker_type == ARROW)
marker.concat_path(arrow_);

path_type path(t_,geom,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
sym.get_spacing() * scale_factor_,
sym.get_max_error(),
sym.get_allow_overlap());
double x_t, y_t, angle;

while (placement.get_point(&x_t, &y_t, &angle))
{
agg::trans_affine matrix;

if (marker_type == ELLIPSE)
{
// todo proper bbox - this is buggy
agg::ellipse c(x_t, y_t, w, h);
marker.concat_path(c);
agg::trans_affine matrix;
matrix *= agg::trans_affine_translation(-x_t,-y_t);
matrix *= agg::trans_affine_rotation(angle);
matrix *= agg::trans_affine_translation(x_t,y_t);
marker.transform(matrix);

}
else
{
matrix = tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x_t, y_t);
}


// TODO
if (writer.first)
//writer.first->add_box(label_ext, feature, t_, writer.second);
std::clog << "### Warning metawriter not yet supported for LINE placement\n";

agg::conv_transform<agg::path_storage, agg::trans_affine> trans(marker, matrix);
ras_ptr->add_path(trans);

// fill
ren.color(agg::rgba8(r, g, b, int(a*sym.get_opacity())));
agg::render_scanlines(*ras_ptr, sl, ren);

// outline
ras_ptr->reset();
agg::conv_stroke<agg::conv_transform<agg::path_storage, agg::trans_affine> > outline(trans);
outline.generator().width(strk_width * scale_factor_);
ras_ptr->add_path(outline);
ren.color(agg::rgba8(s_r, s_g, s_b, int(s_a*stroke_.get_opacity())));
agg::render_scanlines(*ras_ptr, sl_line, ren);
}
}

}
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/load_map.cpp
Expand Up @@ -902,6 +902,26 @@ void map_parser::parse_markers_symbolizer( rule_type & rule, ptree const & sym )
optional<boolean> allow_overlap = get_opt_attr<boolean>(sym, "allow_overlap");
if (allow_overlap) symbol.set_allow_overlap(*allow_overlap);

optional<double> w = get_opt_attr<double>(sym, "width");
if (w) symbol.set_width(*w);
optional<double> h = get_opt_attr<double>(sym, "height");
if (h) symbol.set_height(*h);

stroke strk;
parse_stroke(strk,sym);
symbol.set_stroke(strk);

marker_placement_e placement = get_attr<marker_placement_e>(sym, "placement", MARKER_LINE_PLACEMENT);
symbol.set_marker_placement( placement );

marker_type_e dfl_marker_type = ARROW;

if (placement == MARKER_POINT_PLACEMENT)
dfl_marker_type = ELLIPSE;

marker_type_e marker_type = get_attr<marker_type_e>(sym, "marker_type", dfl_marker_type);
symbol.set_marker_type( marker_type );

parse_metawriter_in_symbolizer(symbol, sym);
rule.append(symbol);
}
Expand Down

0 comments on commit 0cf85f9

Please sign in to comment.