Skip to content

Instantly share code, notes, and snippets.

@pierremarc
Created June 26, 2012 22:27
Show Gist options
  • Save pierremarc/2999728 to your computer and use it in GitHub Desktop.
Save pierremarc/2999728 to your computer and use it in GitHub Desktop.
SVG polygon symbolizer hack / mapnik
diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp
index bf81cc5..0643da0 100644
--- a/src/cairo_renderer.cpp
+++ b/src/cairo_renderer.cpp
@@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
-
+#define HAVE_CAIRO
#if defined(HAVE_CAIRO)
// mapnik
@@ -61,8 +61,17 @@
#include "agg_path_storage.h"
#include "agg_ellipse.h"
+// debug
+#include <iostream>
+
namespace mapnik
{
+
+Cairo::ErrorStatus pseudo_pdf_writer(const unsigned char* /*data*/, unsigned int /*length*/)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
class cairo_pattern : private boost::noncopyable
{
public:
@@ -132,11 +141,31 @@ public:
return pattern_;
}
+ static cairo_pattern* get_pattern(const std::string& key)
+ {
+ if(pat_pool_.find(key) != pat_pool_.end())
+ return pat_pool_.find(key)->second;
+
+ boost::optional<mapnik::marker_ptr> marker = mapnik::marker_cache::instance()->find(key,true);
+ if (!marker && !(*marker)->is_bitmap())
+ {
+ return 0;
+ }
+ cairo_pattern* pat(new cairo_pattern(**((*marker)->get_bitmap_data())));
+ pat_pool_[key] = pat;
+ return pat;
+ }
+
private:
Cairo::RefPtr<Cairo::ImageSurface> surface_;
Cairo::RefPtr<Cairo::SurfacePattern> pattern_;
+
+ static std::map<std::string, cairo_pattern* > pat_pool_;
};
+std::map<std::string, cairo_pattern* > cairo_pattern::pat_pool_ = std::map<std::string, cairo_pattern* >();
+
+
class cairo_gradient : private boost::noncopyable
{
public:
@@ -496,6 +525,7 @@ public:
template <typename T>
void add_agg_path(T& path, unsigned start_index = 0)
{
+// std::cerr<<"ADD_AGG_PATH ======================="<<std::endl;
double x=0;
double y=0;
@@ -506,6 +536,7 @@ public:
if (agg::is_move_to(cm))
{
move_to(x, y);
+// std::cerr<<"M " <<x<<"\t "<<y<<std::endl;
}
else if (agg::is_drawing(cm))
{
@@ -535,6 +566,7 @@ public:
else if (agg::is_line_to(cm))
{
line_to(x, y);
+// std::cerr<<"L " <<x<<"\t "<<y<<std::endl;
}
else
{
@@ -1275,38 +1307,94 @@ void cairo_renderer_base::start_map_processing(Map const& map)
mapnik::feature_ptr const& feature,
proj_transform const& prj_trans)
{
+ typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;
+ typedef coord_transform2<CoordTransform,clipped_geometry_type> path_type;
cairo_context context(context_);
context.set_operator(sym.comp_op());
std::string filename = path_processor_type::evaluate( *sym.get_filename(), *feature);
boost::optional<mapnik::marker_ptr> marker = mapnik::marker_cache::instance()->find(filename,true);
- if (!marker && !(*marker)->is_bitmap()) return;
-
- cairo_pattern pattern(**((*marker)->get_bitmap_data()));
-
- pattern.set_extend(Cairo::EXTEND_REPEAT);
-
- context.set_pattern(pattern);
+ if (!marker)
+ return;
+ if((*marker)->is_bitmap())
+ {
+
+ // cairo_pattern pattern(**((*marker)->get_bitmap_data()));
+ cairo_pattern* pattern(cairo_pattern::get_pattern(filename));
+
+ pattern->set_extend(Cairo::EXTEND_REPEAT);
+
+ context.set_pattern(*pattern);
+
+ typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
+ vertex_converter<box2d<double>,cairo_context,polygon_pattern_symbolizer, proj_transform, CoordTransform, conv_types>
+ converter(query_extent_,context,sym,t_,prj_trans,1.0);
+
+ if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
+ converter.set<transform_tag>(); //always transform
+ converter.set<affine_transform_tag>();
+ if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
+
+ BOOST_FOREACH( geometry_type & geom, feature->paths())
+ {
+ if (geom.num_points() > 2)
+ {
+ converter.apply(geom);
+ }
+ }
+
+ // fill polygon
+ context.fill();
+ }
+ else if((*marker)->is_vector())
+ {
+
+ mapnik::path_ptr mk(*(*marker)->get_vector_data());
+ mapnik::svg::path_attributes attrs(mk->attributes()[0]);
+
+ double dx,dy;
+ attrs.transform.translation(&dx,&dy);
+ agg::path_base<agg::vertex_stl_storage<std::vector<agg::vertex_d> > > agg_path;
+ BOOST_FOREACH(const agg::vertex_d & v, mk->source())
+ {
+ double vx(v.x + dx);
+ double vy(v.y + dy);
+ agg_path.vertices().add_vertex(vx, vy, v.cmd);
+ }
+ double patWidth((*marker)->width());
+ double patHeight((*marker)->height());
+
+ Cairo::RefPtr<Cairo::PdfSurface> patSurface(Cairo::PdfSurface::create_for_stream(sigc::ptr_fun(&(mapnik::pseudo_pdf_writer)), patWidth, patHeight));
+ Cairo::RefPtr<Cairo::Context> const& patContext = Cairo::Context::create(patSurface);
+ mapnik::cairo_context pctx(patContext); // to easily draw agg_path
+ pctx.add_agg_path(agg_path);
+
+ pctx.set_color(attrs.fill_color.r,attrs.fill_color.g,attrs.fill_color.b, attrs.fill_color.a);
+ pctx.set_line_width(attrs.stroke_width);
+ pctx.fill();
+
+ pctx.set_color(attrs.stroke_color.r,attrs.stroke_color.g,attrs.stroke_color.b, attrs.stroke_color.a);
+ pctx.set_line_width(attrs.stroke_width);
+ pctx.stroke();
+
+ Cairo::RefPtr<Cairo::SurfacePattern> patPattern(Cairo::SurfacePattern::create(patSurface));
+ patPattern->set_extend(Cairo::EXTEND_REPEAT);
+ context_->set_source(patPattern);
+
+ BOOST_FOREACH( geometry_type & geom, feature->paths())
+ {
+ if (geom.num_points() > 2)
+ {
+ clipped_geometry_type clipped(geom);
+ clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy());
+ path_type path(t_,clipped,prj_trans);
+ context.add_path(path);
+ }
+ }
+
+ context.fill();
+ }
- typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
- vertex_converter<box2d<double>,cairo_context,polygon_pattern_symbolizer, proj_transform, CoordTransform, conv_types>
- converter(query_extent_,context,sym,t_,prj_trans,1.0);
-
- if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
- converter.set<transform_tag>(); //always transform
- converter.set<affine_transform_tag>();
- if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
-
- BOOST_FOREACH( geometry_type & geom, feature->paths())
- {
- if (geom.num_points() > 2)
- {
- converter.apply(geom);
- }
- }
-
- // fill polygon
- context.fill();
}
void cairo_renderer_base::process(raster_symbolizer const& sym,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment