diff --git a/CHANGELOG b/CHANGELOG index 2e7ad06d0..008cb6d5e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,9 @@ For a complete change history, see the SVN log. Mapnik Trunk ------------ +- Added new rendering backend, grid_renderer, that collects the attributes of rendered features and + burns their ids into a grid buffer. + - Added optional 'maximum-extent' parameter to map object. If set will be used, instead of combined layer extents, for return value of map.zoom_all(). Useful in cases where the combined layer extents cannot possibly be projected into the map srs or the user wishes to control map bounds without diff --git a/include/mapnik/config.hpp b/include/mapnik/config.hpp index c057d655a..2630fecf5 100644 --- a/include/mapnik/config.hpp +++ b/include/mapnik/config.hpp @@ -25,6 +25,8 @@ // Windows DLL support +#define MAPNIK_SUPPORTS_GRID_RENDERER + #ifdef _WINDOWS # define MAPNIK_EXP __declspec (dllexport) # define MAPNIK_IMP __declspec (dllimport) diff --git a/include/mapnik/feature_style_processor.hpp b/include/mapnik/feature_style_processor.hpp index 49cdb41fb..ee745d681 100644 --- a/include/mapnik/feature_style_processor.hpp +++ b/include/mapnik/feature_style_processor.hpp @@ -84,7 +84,7 @@ public: scale_factor_(scale_factor) {} /*! - * @return apply renderer to all maps layers. + * @return apply renderer to all map layers. */ void apply() { @@ -124,6 +124,30 @@ public: p.end_map_processing(m_); } + /*! + * @return apply renderer to a single layer, providing pre-populated set of query attribute names. + */ + void apply(mapnik::layer const& lyr, std::set& names) + { + Processor & p = static_cast(*this); + p.start_map_processing(m_); + try + { + projection proj(m_.srs()); + double scale_denom = mapnik::scale_denominator(m_,proj.is_geographic()); + scale_denom *= scale_factor_; + + if (lyr.isVisible(scale_denom)) + { + apply_to_layer(lyr, p, proj, scale_denom, names); + } + } + catch (proj_init_error& ex) + { + std::clog << "proj_init_error:" << ex.what() << "\n"; + } + p.end_map_processing(m_); + } private: /*! * @return initialize metawriters for a given map and projection. @@ -153,7 +177,7 @@ private: } /*! - * @return render a layer given a projection and scale + * @return render a layer given a projection and scale. */ void apply_to_layer(layer const& lay, Processor & p, projection const& proj0, diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index 8b184c28e..e6fe230a4 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -54,6 +54,7 @@ extern "C" #include #include #include +#include // icu #include @@ -490,6 +491,42 @@ struct text_renderer : private boost::noncopyable } } + void render_id(int feature_id,double x0, double y0, double min_radius=1.0) + { + FT_Error error; + FT_Vector start; + unsigned height = pixmap_.height(); + + start.x = static_cast(x0 * (1 << 6)); + start.y = static_cast((height - y0) * (1 << 6)); + + // now render transformed glyphs + typename glyphs_t::iterator pos; + + stroker_.init(std::max(halo_radius_,min_radius)); + for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) + { + FT_Glyph g; + error = FT_Glyph_Copy(pos->image, &g); + if (!error) + { + FT_Glyph_Transform(g,0,&start); + FT_Glyph_Stroke(&g,stroker_.get(),1); + error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_NORMAL,0,1); + //error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_MONO,0,1); + if ( ! error ) + { + + FT_BitmapGlyph bit = (FT_BitmapGlyph)g; + render_bitmap_id(&bit->bitmap, feature_id, + bit->left, + height - bit->top); + } + } + FT_Done_Glyph(g); + } + } + private: // unused currently, stroker is the new method for drawing halos @@ -535,6 +572,26 @@ private: } } + void render_bitmap_id(FT_Bitmap *bitmap,int feature_id,int x,int y) + { + int x_max=x+bitmap->width; + int y_max=y+bitmap->rows; + int i,p,j,q; + + for (i=x,p=0;ibuffer[q*bitmap->width+p]; + if (gray) + { + pixmap_.setPixel(i,j,feature_id); + //pixmap_.blendPixel2(i,j,rgba,gray,opacity_); + } + } + } + } + pixmap_type & pixmap_; face_set_ptr faces_; stroker & stroker_; diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp new file mode 100644 index 000000000..3588049f9 --- /dev/null +++ b/include/mapnik/grid/grid.hpp @@ -0,0 +1,269 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_GRID_HPP +#define MAPNIK_GRID_HPP + +// mapnik +#include +#include +#include +#include +#include + +// stl +#include +#include +#include +#include +#include + +namespace mapnik +{ + +template +class MAPNIK_DECL hit_grid +{ +public: + typedef T value_type; + typedef mapnik::ImageData data_type; + typedef std::string lookup_type; + // mapping between pixel id and join_field + typedef std::map feature_key_type; + typedef std::map key_type; + typedef std::map feature_properties_type; + // note: feature_type is not the same as a mapnik::Feature as it lacks a geometry + typedef std::map feature_type; + +private: + unsigned width_; + unsigned height_; + std::string join_field_; + key_type keys_; + std::vector key_order_; + feature_key_type f_keys_; + feature_type features_; + data_type data_; + std::set names_; + unsigned int step_; + +public: + + //value_type feature_count_; + std::string id_name_; + + hit_grid(int width, int height, std::string const& join_field, unsigned step) + :width_(width), + height_(height), + join_field_(join_field), + data_(width,height), + step_(step), + //feature_count_(0), + id_name_("__id__") { + f_keys_[0] = ""; + } + + hit_grid(const hit_grid& rhs) + :width_(rhs.width_), + height_(rhs.height_), + join_field_(rhs.join_field_), + data_(rhs.data_), + //feature_count_(0), + step_(rhs.step_), + id_name_("__id__") { + f_keys_[0] = ""; + } + + ~hit_grid() {} + + void add_feature(Feature const& feature) + { + + // copies feature props + std::map fprops = feature.props(); + lookup_type lookup_value; + if (join_field_ == id_name_) + { + // TODO - this will break if lookup_type is not a string + std::stringstream s; + s << feature.id(); + lookup_value = s.str(); + // add this as a proper feature so filtering works later on + fprops[id_name_] = feature.id(); + //fprops[id_name_] = tr_->transcode(lookup_value)); + } + else + { + std::map::const_iterator const& itr = fprops.find(join_field_); + if (itr != fprops.end()) + { + lookup_value = itr->second.to_string(); + } + else + { + std::clog << "should not get here: join_field '" << join_field_ << "' not found in feature properties\n"; + } + } + + // what good is an empty lookup key? + if (!lookup_value.empty()) + { + // TODO - consider shortcutting f_keys if feature_id == lookup_value + // create a mapping between the pixel id and the feature join_field + f_keys_.insert(std::make_pair(feature.id(),lookup_value)); + // if extra fields have been supplied, push them into grid memory + if (!names_.empty()) { + // TODO - add ability to push WKT/WKB of geometry into grid storage + features_.insert(std::make_pair(lookup_value,fprops)); + } + } + else + { + std::clog << "### Warning: join_field '" << join_field_ << "' was blank for " << feature << "\n"; + } + } + + void add_property_name(std::string const& name) + { + names_.insert(name); + } + + std::set property_names() const + { + return names_; + } + + inline const feature_type& get_grid_features() const + { + return features_; + } + + inline feature_type& get_grid_features() + { + return features_; + } + + inline const feature_key_type& get_feature_keys() const + { + return f_keys_; + } + + inline feature_key_type& get_feature_keys() + { + return f_keys_; + } + + inline const std::string& get_join_field() const + { + return join_field_; + } + + inline unsigned int get_step() const + { + return step_; + } + + inline const data_type& data() const + { + return data_; + } + + inline data_type& data() + { + return data_; + } + + inline const T* raw_data() const + { + return data_.getData(); + } + + inline T* raw_data() + { + return data_.getData(); + } + + // TODO - make 'views' generic + inline image_view get_view(unsigned x,unsigned y, unsigned w,unsigned h) + { + return image_view(x,y,w,h,data_); + } + +private: + + inline bool checkBounds(unsigned x, unsigned y) const + { + return (x < width_ && y < height_); + } + + hit_grid& operator=(const hit_grid&); + +public: + inline void setPixel(int x,int y,value_type feature_id) + { + if (checkBounds(x,y)) + { + data_(x,y) = feature_id; + } + } + inline unsigned width() const + { + return width_; + } + + inline unsigned height() const + { + return height_; + } + + inline void set_rectangle(value_type id,image_data_32 const& data,int x0,int y0) + { + box2d ext0(0,0,width_,height_); + box2d ext1(x0,y0,x0+data.width(),y0+data.height()); + + if (ext0.intersects(ext1)) + { + box2d box = ext0.intersect(ext1); + for (int y = box.miny(); y < box.maxy(); ++y) + { + value_type* row_to = data_.getRow(y); + unsigned int const * row_from = data.getRow(y-y0); + + for (int x = box.minx(); x < box.maxx(); ++x) + { + if (row_from[x-x0] & 0xff000000) + { + row_to[x] = id; + } + } + } + } + } + +}; + +//typedef uint16_t value_type; +//typedef unsigned char value_type; +typedef hit_grid grid; + +} +#endif //MAPNIK_GRID_HPP diff --git a/include/mapnik/grid/grid_pixel.hpp b/include/mapnik/grid/grid_pixel.hpp new file mode 100644 index 000000000..a0bbfc59d --- /dev/null +++ b/include/mapnik/grid/grid_pixel.hpp @@ -0,0 +1,170 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_GRID_PIXEL_HPP +#define MAPNIK_GRID_PIXEL_HPP + +#include "agg_basics.h" + +namespace mapnik +{ + + //==================================================================gray16 + struct gray16 + { + typedef agg::int16u value_type; + typedef agg::int32u calc_type; + typedef agg::int64 long_type; + enum base_scale_e + { + base_shift = 16, + base_scale = 1 << base_shift, + base_mask = base_scale - 1 + }; + typedef gray16 self_type; + + value_type v; + value_type a; + + //-------------------------------------------------------------------- + gray16() {} + + //-------------------------------------------------------------------- + gray16(unsigned v_, unsigned a_=base_mask) : + v(agg::int16u(v_)), a(agg::int16u(a_)) {} + + //-------------------------------------------------------------------- + gray16(const self_type& c, unsigned a_) : + v(c.v), a(value_type(a_)) {} + + //-------------------------------------------------------------------- + void clear() + { + v = a = 0; + } + + //-------------------------------------------------------------------- + const self_type& transparent() + { + a = 0; + return *this; + } + + //-------------------------------------------------------------------- + void opacity(double a_) + { + if(a_ < 0.0) a_ = 0.0; + if(a_ > 1.0) a_ = 1.0; + a = (value_type)agg::uround(a_ * double(base_mask)); + } + + //-------------------------------------------------------------------- + double opacity() const + { + return double(a) / double(base_mask); + } + + + //-------------------------------------------------------------------- + const self_type& premultiply() + { + if(a == base_mask) return *this; + if(a == 0) + { + v = 0; + return *this; + } + v = value_type((calc_type(v) * a) >> base_shift); + return *this; + } + + //-------------------------------------------------------------------- + const self_type& premultiply(unsigned a_) + { + if(a == base_mask && a_ >= base_mask) return *this; + if(a == 0 || a_ == 0) + { + v = a = 0; + return *this; + } + calc_type v_ = (calc_type(v) * a_) / a; + v = value_type((v_ > a_) ? a_ : v_); + a = value_type(a_); + return *this; + } + + //-------------------------------------------------------------------- + const self_type& demultiply() + { + if(a == base_mask) return *this; + if(a == 0) + { + v = 0; + return *this; + } + calc_type v_ = (calc_type(v) * base_mask) / a; + v = value_type((v_ > base_mask) ? base_mask : v_); + return *this; + } + + //-------------------------------------------------------------------- + self_type gradient(self_type c, double k) const + { + self_type ret; + calc_type ik = agg::uround(k * base_scale); + ret.v = value_type(calc_type(v) + (((calc_type(c.v) - v) * ik) >> base_shift)); + ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); + return ret; + } + + //-------------------------------------------------------------------- + AGG_INLINE void add(const self_type& c, unsigned cover) + { + calc_type cv, ca; + if(cover == agg::cover_mask) + { + if(c.a == base_mask) + { + *this = c; + } + else + { + cv = v + c.v; v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; + ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; + } + } + else + { + cv = v + ((c.v * cover + agg::cover_mask/2) >> agg::cover_shift); + ca = a + ((c.a * cover + agg::cover_mask/2) >> agg::cover_shift); + v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; + a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; + } + } + + //-------------------------------------------------------------------- + static self_type no_color() { return self_type(0,0); } + }; + +} + +#endif diff --git a/include/mapnik/grid/grid_pixfmt.hpp b/include/mapnik/grid/grid_pixfmt.hpp new file mode 100644 index 000000000..0f3978975 --- /dev/null +++ b/include/mapnik/grid/grid_pixfmt.hpp @@ -0,0 +1,640 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_GRID_PIXFMT_HPP +#define MAPNIK_GRID_PIXFMT_HPP + +#include +#include "agg_basics.h" +#include +#include + +namespace mapnik +{ + + //============================================================blender_gray + template struct blender_gray + { + typedef ColorT color_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e { base_shift = color_type::base_shift }; + + static AGG_INLINE void blend_pix(value_type* p, unsigned cv, + unsigned alpha, unsigned cover=0) + { + *p = (value_type)((((cv - calc_type(*p)) * alpha) + (calc_type(*p) << base_shift)) >> base_shift); + } + }; + + + + //=====================================================apply_gamma_dir_gray + template class apply_gamma_dir_gray + { + public: + typedef typename ColorT::value_type value_type; + + apply_gamma_dir_gray(const GammaLut& gamma) : m_gamma(gamma) {} + + AGG_INLINE void operator () (value_type* p) + { + *p = m_gamma.dir(*p); + } + + private: + const GammaLut& m_gamma; + }; + + + + //=====================================================apply_gamma_inv_gray + template class apply_gamma_inv_gray + { + public: + typedef typename ColorT::value_type value_type; + + apply_gamma_inv_gray(const GammaLut& gamma) : m_gamma(gamma) {} + + AGG_INLINE void operator () (value_type* p) + { + *p = m_gamma.inv(*p); + } + + private: + const GammaLut& m_gamma; + }; + + + + //=================================================pixfmt_alpha_blend_gray + template + class pixfmt_alpha_blend_gray + { + public: + typedef RenBuf rbuf_type; + typedef typename rbuf_type::row_data row_data; + typedef Blender blender_type; + typedef typename blender_type::color_type color_type; + typedef int order_type; // A fake one + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_scale = color_type::base_scale, + base_mask = color_type::base_mask, + pix_width = sizeof(value_type), + pix_step = Step, + pix_offset = Offset + }; + + private: + //-------------------------------------------------------------------- + static AGG_INLINE void copy_or_blend_pix(value_type* p, + const color_type& c, + unsigned cover) + { + if (c.a) + { + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) + { + *p = c.v; + } + else + { + Blender::blend_pix(p, c.v, alpha, cover); + } + } + } + + + static AGG_INLINE void copy_or_blend_pix(value_type* p, + const color_type& c) + { + if (c.a) + { + if(c.a == base_mask) + { + *p = c.v; + } + else + { + Blender::blend_pix(p, c.v, c.a); + } + } + } + + + public: + //-------------------------------------------------------------------- + explicit pixfmt_alpha_blend_gray(rbuf_type& rb) : + m_rbuf(&rb) + {} + void attach(rbuf_type& rb) { m_rbuf = &rb; } + //-------------------------------------------------------------------- + + template + bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) + { + agg::rect_i r(x1, y1, x2, y2); + if(r.clip(agg::rect_i(0, 0, pixf.width()-1, pixf.height()-1))) + { + int stride = pixf.stride(); + m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), + (r.x2 - r.x1) + 1, + (r.y2 - r.y1) + 1, + stride); + return true; + } + return false; + } + + //-------------------------------------------------------------------- + AGG_INLINE unsigned width() const { return m_rbuf->width(); } + AGG_INLINE unsigned height() const { return m_rbuf->height(); } + AGG_INLINE int stride() const { return m_rbuf->stride(); } + + //-------------------------------------------------------------------- + agg::int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } + const agg::int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } + row_data row(int y) const { return m_rbuf->row(y); } + + const agg::int8u* pix_ptr(int x, int y) const + { + return m_rbuf->row_ptr(y) + x * Step + Offset; + } + + agg::int8u* pix_ptr(int x, int y) + { + return m_rbuf->row_ptr(y) + x * Step + Offset; + } + + //-------------------------------------------------------------------- + AGG_INLINE static void make_pix(agg::int8u* p, const color_type& c) + { + *(value_type*)p = c.v; + } + + //-------------------------------------------------------------------- + AGG_INLINE color_type pixel(int x, int y) const + { + value_type* p = (value_type*)m_rbuf->row_ptr(y) + x * Step + Offset; + return color_type(*p); + } + + //-------------------------------------------------------------------- + AGG_INLINE void copy_pixel(int x, int y, const color_type& c) + { + *((value_type*)m_rbuf->row_ptr(x, y, 1) + x * Step + Offset) = c.v; + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_pixel(int x, int y, const color_type& c, agg::int8u cover) + { + copy_or_blend_pix((value_type*) + m_rbuf->row_ptr(x, y, 1) + x * Step + Offset, + c, + cover); + } + + + //-------------------------------------------------------------------- + AGG_INLINE void copy_hline(int x, int y, + unsigned len, + const color_type& c) + { + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + + do + { + *p = c.v; + p += Step; + } + while(--len); + } + + + //-------------------------------------------------------------------- + AGG_INLINE void copy_vline(int x, int y, + unsigned len, + const color_type& c) + { + do + { + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + *p = c.v; + } + while(--len); + } + + + //-------------------------------------------------------------------- + void blend_hline(int x, int y, + unsigned len, + const color_type& c, + agg::int8u cover) + { + if (c.a) + { + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) + { + do + { + *p = c.v; + p += Step; + } + while(--len); + } + else + { + do + { + Blender::blend_pix(p, c.v, alpha, cover); + p += Step; + } + while(--len); + } + } + } + + + //-------------------------------------------------------------------- + void blend_vline(int x, int y, + unsigned len, + const color_type& c, + agg::int8u cover) + { + if (c.a) + { + value_type* p; + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) + { + do + { + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + *p = c.v; + } + while(--len); + } + else + { + do + { + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + Blender::blend_pix(p, c.v, alpha, cover); + } + while(--len); + } + } + } + + + //-------------------------------------------------------------------- + void blend_solid_hspan(int x, int y, + unsigned len, + const color_type& c, + const agg::int8u* covers) + { + if (c.a) + { + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + + do + { + calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; + if(alpha == base_mask) + { + *p = c.v; + } + else + { + Blender::blend_pix(p, c.v, alpha, *covers); + } + p += Step; + ++covers; + } + while(--len); + } + } + + + //-------------------------------------------------------------------- + void blend_solid_vspan(int x, int y, + unsigned len, + const color_type& c, + const agg::int8u* covers) + { + if (c.a) + { + do + { + calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; + + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + if(alpha == base_mask) + { + *p = c.v; + } + else + { + Blender::blend_pix(p, c.v, alpha, *covers); + } + ++covers; + } + while(--len); + } + } + + + //-------------------------------------------------------------------- + void copy_color_hspan(int x, int y, + unsigned len, + const color_type* colors) + { + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + + do + { + *p = colors->v; + p += Step; + ++colors; + } + while(--len); + } + + + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + do + { + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + *p = colors->v; + ++colors; + } + while(--len); + } + + + //-------------------------------------------------------------------- + void blend_color_hspan(int x, int y, + unsigned len, + const color_type* colors, + const agg::int8u* covers, + agg::int8u cover) + { + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + + if(covers) + { + do + { + copy_or_blend_pix(p, *colors++, *covers++); + p += Step; + } + while(--len); + } + else + { + if(cover == 255) + { + do + { + if(colors->a == base_mask) + { + *p = colors->v; + } + else + { + copy_or_blend_pix(p, *colors); + } + p += Step; + ++colors; + } + while(--len); + } + else + { + do + { + copy_or_blend_pix(p, *colors++, cover); + p += Step; + } + while(--len); + } + } + } + + + + //-------------------------------------------------------------------- + void blend_color_vspan(int x, int y, + unsigned len, + const color_type* colors, + const agg::int8u* covers, + agg::int8u cover) + { + value_type* p; + if(covers) + { + do + { + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + copy_or_blend_pix(p, *colors++, *covers++); + } + while(--len); + } + else + { + if(cover == 255) + { + do + { + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + if(colors->a == base_mask) + { + *p = colors->v; + } + else + { + copy_or_blend_pix(p, *colors); + } + ++colors; + } + while(--len); + } + else + { + do + { + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + copy_or_blend_pix(p, *colors++, cover); + } + while(--len); + } + } + } + + //-------------------------------------------------------------------- + template void for_each_pixel(Function f) + { + unsigned y; + for(y = 0; y < height(); ++y) + { + row_data r = m_rbuf->row(y); + if(r.ptr) + { + unsigned len = r.x2 - r.x1 + 1; + + value_type* p = (value_type*) + m_rbuf->row_ptr(r.x1, y, len) + r.x1 * Step + Offset; + + do + { + f(p); + p += Step; + } + while(--len); + } + } + } + + //-------------------------------------------------------------------- + template void apply_gamma_dir(const GammaLut& g) + { + for_each_pixel(apply_gamma_dir_gray(g)); + } + + //-------------------------------------------------------------------- + template void apply_gamma_inv(const GammaLut& g) + { + for_each_pixel(apply_gamma_inv_gray(g)); + } + + //-------------------------------------------------------------------- + template + void copy_from(const RenBuf2& from, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len) + { + const agg::int8u* p = from.row_ptr(ysrc); + if(p) + { + memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, + p + xsrc * pix_width, + len * pix_width); + } + } + + //-------------------------------------------------------------------- + template + void blend_from_color(const SrcPixelFormatRenderer& from, + const color_type& color, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + agg::int8u cover) + { + typedef typename SrcPixelFormatRenderer::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) + { + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; + do + { + copy_or_blend_pix(pdst, + color, + (*psrc * cover + base_mask) >> base_shift); + ++psrc; + ++pdst; + } + while(--len); + } + } + + //-------------------------------------------------------------------- + template + void blend_from_lut(const SrcPixelFormatRenderer& from, + const color_type* color_lut, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + agg::int8u cover) + { + typedef typename SrcPixelFormatRenderer::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) + { + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; + do + { + copy_or_blend_pix(pdst, color_lut[*psrc], cover); + ++psrc; + ++pdst; + } + while(--len); + } + } + + private: + rbuf_type* m_rbuf; + }; + + typedef blender_gray blender_gray16; + + typedef pixfmt_alpha_blend_gray pixfmt_gray16; //----pixfmt_gray16 +} + +#endif + diff --git a/include/mapnik/grid/grid_rasterizer.hpp b/include/mapnik/grid/grid_rasterizer.hpp new file mode 100644 index 000000000..7dc813640 --- /dev/null +++ b/include/mapnik/grid/grid_rasterizer.hpp @@ -0,0 +1,36 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +#ifndef MAPNIK_GRID_RASTERIZER_HPP +#define MAPNIK_GRID_RASTERIZER_HPP + +#include +#include "agg_rasterizer_scanline_aa.h" + +namespace mapnik { + +struct grid_rasterizer : agg::rasterizer_scanline_aa<>, boost::noncopyable {}; + +} + +#endif //MAPNIK_AGG_RASTERIZER_HPP diff --git a/include/mapnik/grid/grid_renderer.hpp b/include/mapnik/grid/grid_renderer.hpp new file mode 100644 index 000000000..6f15cd13b --- /dev/null +++ b/include/mapnik/grid/grid_renderer.hpp @@ -0,0 +1,125 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +//$Id$ + +#ifndef GRID_RENDERER_HPP +#define GRID_RENDERER_HPP + +// mapnik +#include +#include +#include +#include +#include +#include +//#include + +#include + +// boost +#include +#include + +// FIXME +// forward declare so that +// apps using mapnik do not +// need agg headers +namespace agg { + struct trans_affine; +} + +namespace mapnik { + +class marker; + +struct grid_rasterizer; + +template +class MAPNIK_DECL grid_renderer : public feature_style_processor >, + private boost::noncopyable +{ + +public: + grid_renderer(Map const& m, T & pixmap, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); + ~grid_renderer(); + void start_map_processing(Map const& map); + void end_map_processing(Map const& map); + void start_layer_processing(layer const& lay); + void end_layer_processing(layer const& lay); + void render_marker(Feature const& feature, unsigned int step, const int x, const int y, marker &marker, const agg::trans_affine & tr, double opacity); + + void process(point_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(line_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(line_pattern_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(polygon_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(polygon_pattern_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(raster_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(shield_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(text_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(building_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(markers_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + void process(glyph_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans); + inline bool process(rule::symbolizers const& /*syms*/, + Feature const& /*feature*/, + proj_transform const& /*prj_trans*/) + { + // grid renderer doesn't support processing of multiple symbolizers. + return false; + }; + +private: + T & pixmap_; + unsigned width_; + unsigned height_; + double scale_factor_; + CoordTransform t_; + freetype_engine font_engine_; + face_manager font_manager_; + label_collision_detector4 detector_; + boost::scoped_ptr ras_ptr; +}; +} + +#endif //GRID_RENDERER_HPP diff --git a/include/mapnik/grid/grid_rendering_buffer.hpp b/include/mapnik/grid/grid_rendering_buffer.hpp new file mode 100644 index 000000000..a6433782a --- /dev/null +++ b/include/mapnik/grid/grid_rendering_buffer.hpp @@ -0,0 +1,36 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +#ifndef MAPNIK_GRID_RENDERING_BUFFER_HPP +#define MAPNIK_GRID_RENDERING_BUFFER_HPP + +#include +#include "agg_rendering_buffer.h" + +namespace mapnik { + +typedef agg::row_ptr_cache grid_rendering_buffer; + +} + +#endif //MAPNIK_AGG_RASTERIZER_HPP diff --git a/include/mapnik/svg/svg_renderer.hpp b/include/mapnik/svg/svg_renderer.hpp index 14dc3507f..81377b133 100644 --- a/include/mapnik/svg/svg_renderer.hpp +++ b/include/mapnik/svg/svg_renderer.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -343,6 +344,93 @@ public: } } + template + void render_id(Rasterizer& ras, + Scanline& sl, + Renderer& ren, + int feature_id, + agg::trans_affine const& mtx, + double opacity, + const box2d &symbol_bbox) + + { + using namespace agg; + + trans_affine transform; + curved_stroked_trans_type curved_stroked_trans(curved_stroked_,transform); + curved_trans_type curved_trans(curved_,transform); + curved_trans_contour_type curved_trans_contour(curved_trans); + + curved_trans_contour.auto_detect_orientation(true); + + for(unsigned i = 0; i < attributes_.size(); ++i) + { + mapnik::svg::path_attributes const& attr = attributes_[i]; + if (!attr.visibility_flag) + continue; + + transform = attr.transform; + + double bx1,by1,bx2,by2; + bounding_rect_single(curved_trans, attr.index, &bx1, &by1, &bx2, &by2); + box2d path_bbox(bx1,by1,bx2,by2); + + transform *= mtx; + double scl = transform.scale(); + //curved_.approximation_method(curve_inc); + curved_.approximation_scale(scl); + curved_.angle_tolerance(0.0); + + mapnik::gray16 color(feature_id); + + if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT) + { + ras.reset(); + + if(fabs(curved_trans_contour.width()) < 0.0001) + { + ras.add_path(curved_trans, attr.index); + } + else + { + curved_trans_contour.miter_limit(attr.miter_limit); + ras.add_path(curved_trans_contour, attr.index); + } + + ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero); + renderer_solid ren_s(ren); + ren_s.color(color); + render_scanlines(ras, sl, ren_s); + } + + if (attr.stroke_flag || attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) + { + curved_stroked_.width(attr.stroke_width); + //m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join); + curved_stroked_.line_join(attr.line_join); + curved_stroked_.line_cap(attr.line_cap); + curved_stroked_.miter_limit(attr.miter_limit); + curved_stroked_.inner_join(inner_round); + curved_stroked_.approximation_scale(scl); + + // If the *visual* line width is considerable we + // turn on processing of curve cusps. + //--------------------- + if(attr.stroke_width * scl > 1.0) + { + curved_.angle_tolerance(0.2); + } + ras.reset(); + ras.add_path(curved_stroked_trans, attr.index); + + ras.filling_rule(fill_non_zero); + renderer_solid ren_s(ren); + ren_s.color(color); + render_scanlines(ras, sl, ren_s); + } + } + } + private: VertexSource & source_; diff --git a/src/SConscript b/src/SConscript index 6a3dae9b4..e30bd69a2 100644 --- a/src/SConscript +++ b/src/SConscript @@ -144,10 +144,14 @@ source = Split( metawriter_inmem.cpp metawriter_factory.cpp mapped_memory_cache.cpp + marker_cache.cpp + svg_parser.cpp + svg_path_parser.cpp + svg_points_parser.cpp + svg_transform_parser.cpp """ ) - # add the datasource_cache.cpp with custom LIBTOOL flag if needed if env['LIBTOOL_SUPPORTS_ADVISE']: env3 = lib_env.Clone() @@ -162,9 +166,9 @@ if env['JPEG']: jpeg_reader.cpp """) -if True : # agg backend - source += Split( - """ +# agg backend +source += Split( + """ agg/agg_renderer.cpp agg/process_building_symbolizer.cpp agg/process_glyph_symbolizer.cpp @@ -177,13 +181,46 @@ if True : # agg backend agg/process_raster_symbolizer.cpp agg/process_shield_symbolizer.cpp agg/process_markers_symbolizer.cpp - svg_parser.cpp - svg_path_parser.cpp - svg_points_parser.cpp - svg_transform_parser.cpp - marker_cache.cpp """ - ) + ) + +# grid backend +source += Split( + """ + grid/grid_renderer.cpp + grid/process_building_symbolizer.cpp + grid/process_glyph_symbolizer.cpp + grid/process_line_pattern_symbolizer.cpp + grid/process_line_symbolizer.cpp + grid/process_markers_symbolizer.cpp + grid/process_point_symbolizer.cpp + grid/process_polygon_pattern_symbolizer.cpp + grid/process_polygon_symbolizer.cpp + grid/process_raster_symbolizer.cpp + grid/process_shield_symbolizer.cpp + grid/process_text_symbolizer.cpp + """) + +if env['SVG_RENDERER']: # svg backend + source += Split( + """ + svg/svg_renderer.cpp + svg/svg_generator.cpp + svg/svg_output_attributes.cpp + svg/process_symbolizers.cpp + svg/process_building_symbolizer.cpp + svg/process_glyph_symbolizer.cpp + svg/process_line_pattern_symbolizer.cpp + svg/process_line_symbolizer.cpp + svg/process_markers_symbolizer.cpp + svg/process_point_symbolizer.cpp + svg/process_polygon_pattern_symbolizer.cpp + svg/process_polygon_symbolizer.cpp + svg/process_raster_symbolizer.cpp + svg/process_shield_symbolizer.cpp + svg/process_text_symbolizer.cpp + """) + lib_env.Append(CXXFLAGS = '-DSVG_RENDERER') if env['HAS_CAIRO']: # attach libs to library linking environment @@ -223,27 +260,6 @@ elif env['XMLPARSER'] == 'libxml2' and env['HAS_LIBXML2']: source.remove(cpp) source.insert(0,env2.SharedObject(cpp)) -if env['SVG_RENDERER']: # svg backend - source += Split( - """ - svg/svg_renderer.cpp - svg/svg_generator.cpp - svg/svg_output_attributes.cpp - svg/process_symbolizers.cpp - svg/process_building_symbolizer.cpp - svg/process_glyph_symbolizer.cpp - svg/process_line_pattern_symbolizer.cpp - svg/process_line_symbolizer.cpp - svg/process_markers_symbolizer.cpp - svg/process_point_symbolizer.cpp - svg/process_polygon_pattern_symbolizer.cpp - svg/process_polygon_symbolizer.cpp - svg/process_raster_symbolizer.cpp - svg/process_shield_symbolizer.cpp - svg/process_text_symbolizer.cpp - """) - lib_env.Append(CXXFLAGS = '-DSVG_RENDERER') - if env['CUSTOM_LDFLAGS']: linkflags = '%s %s' % (env['CUSTOM_LDFLAGS'], mapnik_lib_link_flag) else: @@ -299,16 +315,20 @@ else: includes = glob.glob('../include/mapnik/*.hpp') svg_includes = glob.glob('../include/mapnik/svg/*.hpp') wkt_includes = glob.glob('../include/mapnik/wkt/*.hpp') +grid_includes = glob.glob('../include/mapnik/grid/*.hpp') inc_target = os.path.normpath(install_prefix+'/include/mapnik') svg_inc_target = os.path.normpath(install_prefix+'/include/mapnik/svg') wkt_inc_target = os.path.normpath(install_prefix+'/include/mapnik/wkt') +grid_inc_target = os.path.normpath(install_prefix+'/include/mapnik/grid') if 'uninstall' not in COMMAND_LINE_TARGETS: env.Alias(target='install', source=env.Install(inc_target, includes)) env.Alias(target='install', source=env.Install(svg_inc_target, svg_includes)) env.Alias(target='install', source=env.Install(wkt_inc_target, wkt_includes)) + env.Alias(target='install', source=env.Install(grid_inc_target, grid_includes)) env['create_uninstall_target'](env, inc_target) env['create_uninstall_target'](env, svg_inc_target) env['create_uninstall_target'](env, wkt_inc_target) +env['create_uninstall_target'](env, grid_inc_target) diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp new file mode 100644 index 000000000..1c26dc548 --- /dev/null +++ b/src/grid/grid_renderer.cpp @@ -0,0 +1,162 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// boost +#include + +// stl +#ifdef MAPNIK_DEBUG +#include +#endif + +//#include + +namespace mapnik +{ + +template +grid_renderer::grid_renderer(Map const& m, T & pixmap, double scale_factor, unsigned offset_x, unsigned offset_y) + : feature_style_processor(m, scale_factor), + pixmap_(pixmap), + width_(pixmap_.width()), + height_(pixmap_.height()), + scale_factor_(scale_factor), + t_(pixmap_.width(),pixmap_.width(),m.get_current_extent(),offset_x,offset_y), + font_engine_(), + font_manager_(font_engine_), + detector_(box2d(-m.buffer_size(), -m.buffer_size(), pixmap_.width() + m.buffer_size(), pixmap_.height() + m.buffer_size())), + ras_ptr(new grid_rasterizer) +{ +#ifdef MAPNIK_DEBUG + std::clog << "scale=" << m.scale() << "\n"; +#endif +} + +template +grid_renderer::~grid_renderer() {} + +template +void grid_renderer::start_map_processing(Map const& map) +{ +#ifdef MAPNIK_DEBUG + std::clog << "start map processing bbox=" + << map.get_current_extent() << "\n"; +#endif + ras_ptr->clip_box(0,0,width_,height_); +} + +template +void grid_renderer::end_map_processing(Map const& ) +{ +#ifdef MAPNIK_DEBUG + std::clog << "end map processing\n"; +#endif +} + +template +void grid_renderer::start_layer_processing(layer const& lay) +{ +#ifdef MAPNIK_DEBUG + std::clog << "start layer processing : " << lay.name() << "\n"; + std::clog << "datasource = " << lay.datasource().get() << "\n"; +#endif + if (lay.clear_label_cache()) + { + detector_.clear(); + } +} + +template +void grid_renderer::end_layer_processing(layer const&) +{ +#ifdef MAPNIK_DEBUG + std::clog << "end layer processing\n"; +#endif +} + +template +void grid_renderer::render_marker(Feature const& feature, unsigned int step, const int x, const int y, marker &marker, const agg::trans_affine & tr, double opacity) +{ + if (marker.is_vector()) + { + typedef coord_transform2 path_type; + typedef agg::renderer_base ren_base; + typedef agg::renderer_scanline_aa_solid renderer; + agg::scanline_u8 sl; + + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray16 pixf(buf); + + ren_base renb(pixf); + renderer ren(renb); + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_linear(0.0, 0.0)); + + + box2d const& bbox = (*marker.get_vector_data())->bounding_box(); + coord c = bbox.center(); + // center the svg marker on '0,0' + agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); + // apply symbol transformation to get to map space + mtx *= tr; + mtx *= agg::trans_affine_scaling(scale_factor_*(1.0/step)); + // render the marker at the center of the marker box + mtx.translate(x+0.5 * marker.width(), y+0.5 * marker.height()); + + vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + svg_path_adapter svg_path(stl_storage); + svg_renderer, mapnik::pixfmt_gray16 > svg_renderer(svg_path, + (*marker.get_vector_data())->attributes()); + + svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), mtx, opacity, bbox); + + } + else + { + pixmap_.set_rectangle(feature.id(), **marker.get_bitmap_data(), x, y); + } + pixmap_.add_feature(feature); +} + +template class grid_renderer; +} diff --git a/src/grid/process_building_symbolizer.cpp b/src/grid/process_building_symbolizer.cpp new file mode 100644 index 000000000..be175198b --- /dev/null +++ b/src/grid/process_building_symbolizer.cpp @@ -0,0 +1,160 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include +#include + +// boost +#include + +// agg +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_scanline_u.h" +#include "agg_conv_stroke.h" + +// agg +/*#include "agg_basics.h" +#include "agg_rendering_buffer.h" +#include "agg_pixfmt_rgba.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_scanline_u.h" +#include "agg_renderer_scanline.h" +#include "agg_conv_stroke.h" +*/ + +namespace mapnik +{ + +template +void grid_renderer::process(building_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + typedef coord_transform2 path_type; + typedef agg::renderer_base ren_base; + typedef agg::renderer_scanline_aa_solid renderer; + agg::scanline_u8 sl; + + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray16 pixf(buf); + + ren_base renb(pixf); + renderer ren(renb); + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_linear(0.0, 0.0)); + + double height = sym.height() * scale_factor_; + + for (unsigned i=0;i 2) + { + boost::scoped_ptr frame(new geometry_type(LineString)); + boost::scoped_ptr roof(new geometry_type(Polygon)); + std::deque face_segments; + double x0(0); + double y0(0); + unsigned cm = geom.vertex(&x0,&y0); + for (unsigned j=1;jmove_to(x,y); + } + else if (cm == SEG_LINETO) + { + frame->line_to(x,y); + face_segments.push_back(segment_t(x0,y0,x,y)); + } + + x0 = x; + y0 = y; + } + std::sort(face_segments.begin(),face_segments.end(), y_order); + std::deque::const_iterator itr=face_segments.begin(); + for (;itr!=face_segments.end();++itr) + { + boost::scoped_ptr faces(new geometry_type(Polygon)); + faces->move_to(itr->get<0>(),itr->get<1>()); + faces->line_to(itr->get<2>(),itr->get<3>()); + faces->line_to(itr->get<2>(),itr->get<3>() + height); + faces->line_to(itr->get<0>(),itr->get<1>() + height); + + path_type faces_path (t_,*faces,prj_trans); + ras_ptr->add_path(faces_path); + ren.color(mapnik::gray16(feature.id())); + agg::render_scanlines(*ras_ptr, sl, ren); + ras_ptr->reset(); + + frame->move_to(itr->get<0>(),itr->get<1>()); + frame->line_to(itr->get<0>(),itr->get<1>()+height); + } + + geom.rewind(0); + for (unsigned j=0;jmove_to(x,y+height); + roof->move_to(x,y+height); + } + else if (cm == SEG_LINETO) + { + frame->line_to(x,y+height); + roof->line_to(x,y+height); + } + } + path_type path(t_,*frame,prj_trans); + agg::conv_stroke stroke(path); + ras_ptr->add_path(stroke); + ren.color(mapnik::gray16(feature.id())); + agg::render_scanlines(*ras_ptr, sl, ren); + ras_ptr->reset(); + + path_type roof_path (t_,*roof,prj_trans); + ras_ptr->add_path(roof_path); + ren.color(mapnik::gray16(feature.id())); + agg::render_scanlines(*ras_ptr, sl, ren); + } + } + pixmap_.add_feature(feature); +} + +template void grid_renderer::process(building_symbolizer const&, + Feature const&, + proj_transform const&); + +} diff --git a/src/grid/process_glyph_symbolizer.cpp b/src/grid/process_glyph_symbolizer.cpp new file mode 100644 index 000000000..b21453a7a --- /dev/null +++ b/src/grid/process_glyph_symbolizer.cpp @@ -0,0 +1,41 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include + +namespace mapnik { + +template +void grid_renderer::process(glyph_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + std::clog << "grid_renderer does not yet support glyph_symbolizer\n"; +} + +template void grid_renderer::process(glyph_symbolizer const&, + Feature const&, + proj_transform const&); +} diff --git a/src/grid/process_line_pattern_symbolizer.cpp b/src/grid/process_line_pattern_symbolizer.cpp new file mode 100644 index 000000000..1c2c77814 --- /dev/null +++ b/src/grid/process_line_pattern_symbolizer.cpp @@ -0,0 +1,93 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include + +// agg +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_scanline_p.h" +#include "agg_conv_stroke.h" +#include "agg_conv_dash.h" + +// stl +#include + +namespace mapnik { + +template +void grid_renderer::process(line_pattern_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + typedef coord_transform2 path_type; + typedef agg::renderer_base ren_base; + typedef agg::renderer_scanline_aa_solid renderer; + agg::scanline_p8 sl; + + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray16 pixf(buf); + + ren_base renb(pixf); + renderer ren(renb); + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_linear(0.0, 0.0)); + + // TODO - actually handle image dimensions + int stroke_width = 2; + + for (unsigned i=0;i 1) + { + path_type path(t_,geom,prj_trans); + agg::conv_stroke stroke(path); + stroke.generator().miter_limit(4.0); + stroke.generator().width(stroke_width * scale_factor_); + ras_ptr->add_path(stroke); + } + } + + // render id + ren.color(mapnik::gray16(feature.id())); + agg::render_scanlines(*ras_ptr, sl, ren); + + // add feature properties to grid cache + pixmap_.add_feature(feature); + +} + + +template void grid_renderer::process(line_pattern_symbolizer const&, + Feature const&, + proj_transform const&); + +} + diff --git a/src/grid/process_line_symbolizer.cpp b/src/grid/process_line_symbolizer.cpp new file mode 100644 index 000000000..4e956ced8 --- /dev/null +++ b/src/grid/process_line_symbolizer.cpp @@ -0,0 +1,153 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include + +// agg +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_scanline_p.h" +#include "agg_conv_stroke.h" +#include "agg_conv_dash.h" + +// stl +#include + +namespace mapnik { + +template +void grid_renderer::process(line_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + typedef coord_transform2 path_type; + typedef agg::renderer_base ren_base; + typedef agg::renderer_scanline_aa_solid renderer; + //agg::scanline_u8 sl; + agg::scanline_p8 sl; + + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray16 pixf(buf); + + ren_base renb(pixf); + renderer ren(renb); + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_linear(0.0, 0.0)); + + stroke const& stroke_ = sym.get_stroke(); + + for (unsigned i=0;i 1) + { + path_type path(t_,geom,prj_trans); + + if (stroke_.has_dash()) + { + agg::conv_dash dash(path); + dash_array const& d = stroke_.get_dash_array(); + dash_array::const_iterator itr = d.begin(); + dash_array::const_iterator end = d.end(); + for (;itr != end;++itr) + { + dash.add_dash(itr->first * scale_factor_, + itr->second * scale_factor_); + } + + agg::conv_stroke > stroke(dash); + + line_join_e join=stroke_.get_line_join(); + if ( join == MITER_JOIN) + stroke.generator().line_join(agg::miter_join); + else if( join == MITER_REVERT_JOIN) + stroke.generator().line_join(agg::miter_join); + else if( join == ROUND_JOIN) + stroke.generator().line_join(agg::round_join); + else + stroke.generator().line_join(agg::bevel_join); + + line_cap_e cap=stroke_.get_line_cap(); + if (cap == BUTT_CAP) + stroke.generator().line_cap(agg::butt_cap); + else if (cap == SQUARE_CAP) + stroke.generator().line_cap(agg::square_cap); + else + stroke.generator().line_cap(agg::round_cap); + + stroke.generator().miter_limit(4.0); + stroke.generator().width(stroke_.get_width() * scale_factor_); + + ras_ptr->add_path(stroke); + + } + else + { + agg::conv_stroke stroke(path); + line_join_e join=stroke_.get_line_join(); + if ( join == MITER_JOIN) + stroke.generator().line_join(agg::miter_join); + else if( join == MITER_REVERT_JOIN) + stroke.generator().line_join(agg::miter_join); + else if( join == ROUND_JOIN) + stroke.generator().line_join(agg::round_join); + else + stroke.generator().line_join(agg::bevel_join); + + line_cap_e cap=stroke_.get_line_cap(); + if (cap == BUTT_CAP) + stroke.generator().line_cap(agg::butt_cap); + else if (cap == SQUARE_CAP) + stroke.generator().line_cap(agg::square_cap); + else + stroke.generator().line_cap(agg::round_cap); + + stroke.generator().miter_limit(4.0); + stroke.generator().width(stroke_.get_width() * scale_factor_); + ras_ptr->add_path(stroke); + } + } + } + + // render id + ren.color(mapnik::gray16(feature.id())); + agg::render_scanlines(*ras_ptr, sl, ren); + + // add feature properties to grid cache + pixmap_.add_feature(feature); + +} + + +template void grid_renderer::process(line_symbolizer const&, + Feature const&, + proj_transform const&); + +} + diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp new file mode 100644 index 000000000..b681942bb --- /dev/null +++ b/src/grid/process_markers_symbolizer.cpp @@ -0,0 +1,263 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2010 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// agg +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.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" + +// stl +#include + + + +namespace mapnik { + +template +void grid_renderer::process(markers_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + typedef coord_transform2 path_type; + typedef agg::renderer_base ren_base; + typedef agg::renderer_scanline_aa_solid renderer; + agg::scanline_u8 sl; + agg::scanline_p8 sl_line; + + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray16 pixf(buf); + + ren_base renb(pixf); + renderer ren(renb); + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_linear(0.0, 0.0)); + + agg::trans_affine tr; + boost::array const& m = sym.get_transform(); + tr.load_from(&m[0]); + tr = agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_step())) * 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(); + + if (!filename.empty()) + { + boost::optional mark = mapnik::marker_cache::instance()->find(filename, true); + if (mark && *mark && (*mark)->is_vector()) + { + boost::optional marker = (*mark)->get_vector_data(); + box2d const& bbox = (*marker)->bounding_box(); + double x1 = bbox.minx(); + double y1 = bbox.miny(); + double x2 = bbox.maxx(); + double y2 = bbox.maxy(); + + agg::trans_affine recenter = agg::trans_affine_translation(-0.5*(x1+x2),-0.5*(y1+y2)); + tr.transform(&x1,&y1); + tr.transform(&x2,&y2); + box2d extent(x1,y1,x2,y2); + using namespace mapnik::svg; + vertex_stl_adapter stl_storage((*marker)->source()); + svg_path_adapter svg_path(stl_storage); + svg_renderer, mapnik::pixfmt_gray16 > svg_renderer(svg_path,(*marker)->attributes()); + + bool placed = false; + for (unsigned i=0; i 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)) + { + placed = true; + agg::trans_affine matrix = recenter * tr *agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y); + svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(),bbox); + } + } + if (placed) + pixmap_.add_feature(feature); + } + } + else + { + stroke const& stroke_ = sym.get_stroke(); + double strk_width = stroke_.get_width(); + + // clamp to at least 4 px otherwise interactive pixels can be too small + double min = static_cast(4/pixmap_.get_step()); + double w = std::max(sym.get_width()/pixmap_.get_step(),min); + double h = std::max(sym.get_height()/pixmap_.get_step(),min); + + arrow arrow_; + box2d 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); + } + 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); + } + + double x; + double y; + double z=0; + + for (unsigned i=0; i 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); + agg::path_storage marker; + marker.concat_path(c); + ras_ptr->add_path(marker); + + // outline + if (strk_width) + { + agg::conv_stroke outline(marker); + outline.generator().width(strk_width * scale_factor_); + ras_ptr->add_path(outline); + } + + detector_.insert(label_ext); + } + } + else + { + + agg::path_storage marker; + if (marker_type == ARROW) + marker.concat_path(arrow_); + + path_type path(t_,geom,prj_trans); + markers_placement 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); + } + + agg::conv_transform trans(marker, matrix); + + // fill + ras_ptr->add_path(trans); + + // outline + if (strk_width) + { + agg::conv_stroke > outline(trans); + outline.generator().width(strk_width * scale_factor_); + ras_ptr->add_path(outline); + } + } + } + + } + ren.color(mapnik::gray16(feature.id())); + agg::render_scanlines(*ras_ptr, sl, ren); + pixmap_.add_feature(feature); + } +} + +template void grid_renderer::process(markers_symbolizer const&, + Feature const&, + proj_transform const&); +} diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp new file mode 100644 index 000000000..3b7e0570c --- /dev/null +++ b/src/grid/process_point_symbolizer.cpp @@ -0,0 +1,99 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include + +#include + +// stl +#include + +namespace mapnik { + +template +void grid_renderer::process(point_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); + + boost::optional marker; + if ( !filename.empty() ) + { + marker = marker_cache::instance()->find(filename, true); + } + else + { + marker.reset(boost::shared_ptr (new mapnik::marker())); + } + + if (marker) + { + for (unsigned i=0; iwidth(); + int h = (*marker)->height(); + + int px = int(floor(x - 0.5 * w)); + int py = int(floor(y - 0.5 * h)); + box2d label_ext (px, py, px + w, py + h); + if (sym.get_allow_overlap() || + detector_.has_placement(label_ext)) + { + agg::trans_affine tr; + boost::array const& m = sym.get_transform(); + tr.load_from(&m[0]); + + render_marker(feature,pixmap_.get_step(),px,py,**marker,tr, sym.get_opacity()); + + if (!sym.get_ignore_placement()) + detector_.insert(label_ext); + } + } + } + +} + +template void grid_renderer::process(point_symbolizer const&, + Feature const&, + proj_transform const&); + +} + diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp new file mode 100644 index 000000000..ea32237d8 --- /dev/null +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -0,0 +1,84 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include + +// agg +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_scanline_u.h" + +// stl +#include +#include + +namespace mapnik { + +template +void grid_renderer::process(polygon_pattern_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + typedef coord_transform2 path_type; + typedef agg::renderer_base ren_base; + typedef agg::renderer_scanline_aa_solid renderer; + agg::scanline_u8 sl; + + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray16 pixf(buf); + + ren_base renb(pixf); + renderer ren(renb); + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_linear(0.0, 0.0)); + for (unsigned i=0;i 2) + { + path_type path(t_,geom,prj_trans); + ras_ptr->add_path(path); + } + } + + // render id + ren.color(mapnik::gray16(feature.id())); + agg::render_scanlines(*ras_ptr, sl, ren); + + // add feature properties to grid cache + pixmap_.add_feature(feature); +} + + +template void grid_renderer::process(polygon_pattern_symbolizer const&, + Feature const&, + proj_transform const&); + +} + diff --git a/src/grid/process_polygon_symbolizer.cpp b/src/grid/process_polygon_symbolizer.cpp new file mode 100644 index 000000000..b0c01d072 --- /dev/null +++ b/src/grid/process_polygon_symbolizer.cpp @@ -0,0 +1,87 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include + +// agg +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_scanline_u.h" + +// stl +#include +#include + +namespace mapnik { + +template +void grid_renderer::process(polygon_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + typedef coord_transform2 path_type; + typedef agg::renderer_base ren_base; + typedef agg::renderer_scanline_aa_solid renderer; + agg::scanline_u8 sl; + + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray16 pixf(buf); + + ren_base renb(pixf); + renderer ren(renb); + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_linear(0.0, 0.0)); + for (unsigned i=0;i 2) + { + path_type path(t_,geom,prj_trans); + ras_ptr->add_path(path); + } + } + + // render id + ren.color(mapnik::gray16(feature.id())); + agg::render_scanlines(*ras_ptr, sl, ren); + + // add feature properties to grid cache + pixmap_.add_feature(feature); + + // increment feature count + //++pixmap_.feature_count_; +} + + +template void grid_renderer::process(polygon_symbolizer const&, + Feature const&, + proj_transform const&); + +} + diff --git a/src/grid/process_raster_symbolizer.cpp b/src/grid/process_raster_symbolizer.cpp new file mode 100644 index 000000000..23a011038 --- /dev/null +++ b/src/grid/process_raster_symbolizer.cpp @@ -0,0 +1,42 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include + +namespace mapnik { + + +template +void grid_renderer::process(raster_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + std::clog << "grid_renderer does not yet support raster_symbolizer\n"; +} + +template void grid_renderer::process(raster_symbolizer const&, + Feature const&, + proj_transform const&); + +} diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp new file mode 100644 index 000000000..69a43b8a3 --- /dev/null +++ b/src/grid/process_shield_symbolizer.cpp @@ -0,0 +1,251 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// agg +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_scanline_u.h" + +namespace mapnik { + +template +void grid_renderer::process(shield_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + typedef coord_transform2 path_type; + + bool placement_found = false; + + text_placement_info_ptr placement_options = sym.get_placement_options()->get_placement_info(); + placement_options->next(); + placement_options->next_position_only(); + + UnicodeString text; + if( sym.get_no_text() ) + text = UnicodeString( " " ); // TODO: fix->use 'space' as the text to render + else + { + expression_ptr name_expr = sym.get_name(); + if (!name_expr) return; + value_type result = boost::apply_visitor(evaluate(feature),*name_expr); + text = result.to_unicode(); + } + + if ( sym.get_text_transform() == UPPERCASE) + { + text = text.toUpper(); + } + else if ( sym.get_text_transform() == LOWERCASE) + { + text = text.toLower(); + } + else if ( sym.get_text_transform() == CAPITALIZE) + { + text = text.toTitle(NULL); + } + + agg::trans_affine tr; + boost::array const& m = sym.get_transform(); + tr.load_from(&m[0]); + tr = agg::trans_affine_scaling(scale_factor_) * tr; + + std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature); + boost::optional marker; + if ( !filename.empty() ) + { + marker = marker_cache::instance()->find(filename, true); + } + else + { + marker.reset(boost::shared_ptr (new mapnik::marker())); + } + + if (text.length() > 0 && marker) + { + face_set_ptr faces; + + if (sym.get_fontset().size() > 0) + { + faces = font_manager_.get_face_set(sym.get_fontset()); + } + else + { + faces = font_manager_.get_face_set(sym.get_face_name()); + } + + stroker_ptr strk = font_manager_.get_stroker(); + if (strk && faces->size() > 0) + { + text_renderer ren(pixmap_, faces, *strk); + + ren.set_pixel_size(sym.get_text_size() * scale_factor_ * (1.0/pixmap_.get_step())); + ren.set_fill(sym.get_fill()); + ren.set_halo_fill(sym.get_halo_fill()); + ren.set_halo_radius(sym.get_halo_radius() * scale_factor_); + ren.set_opacity(sym.get_text_opacity()); + + placement_finder finder(detector_); + + string_info info(text); + + faces->get_string_info(info); + + // TODO- clamp to at least 4 px otherwise interactivity is too small + int w = (*marker)->width()/pixmap_.get_step(); + int h = (*marker)->height()/pixmap_.get_step(); + + for (unsigned i = 0; i < feature.num_geometries(); ++i) + { + geometry_type const& geom = feature.get_geometry(i); + if (geom.num_points() > 0 ) + { + path_type path(t_,geom,prj_trans); + + label_placement_enum how_placed = sym.get_label_placement(); + if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT || how_placed == INTERIOR_PLACEMENT) + { + // for every vertex, try and place a shield/text + geom.rewind(0); + placement text_placement(info, sym, placement_options, scale_factor_, w, h, false); + text_placement.avoid_edges = sym.get_avoid_edges(); + text_placement.allow_overlap = sym.get_allow_overlap(); + position const& pos = sym.get_displacement(); + position const& shield_pos = sym.get_shield_displacement(); + for( unsigned jj = 0; jj < geom.num_points(); jj++ ) + { + double label_x; + double label_y; + double z=0.0; + + if( how_placed == VERTEX_PLACEMENT ) + geom.vertex(&label_x,&label_y); // by vertex + else if( how_placed == INTERIOR_PLACEMENT ) + geom.label_interior_position(&label_x,&label_y); + else + geom.label_position(&label_x, &label_y); // by middle of line or by point + prj_trans.backward(label_x,label_y, z); + t_.forward(&label_x,&label_y); + + label_x += boost::get<0>(shield_pos); + label_y += boost::get<1>(shield_pos); + + finder.find_point_placement( text_placement,label_x,label_y,0.0, + sym.get_vertical_alignment(), + sym.get_line_spacing(), + sym.get_character_spacing(), + sym.get_horizontal_alignment(), + sym.get_justify_alignment() ); + + // check to see if image overlaps anything too, there is only ever 1 placement found for points and verticies + if( text_placement.placements.size() > 0) + { + placement_found = true; + double x = floor(text_placement.placements[0].starting_x); + double y = floor(text_placement.placements[0].starting_y); + int px; + int py; + box2d label_ext; + + if( !sym.get_unlock_image() ) + { + // center image at text center position + // remove displacement from image label + double lx = x - boost::get<0>(pos); + double ly = y - boost::get<1>(pos); + px=int(floor(lx - (0.5 * w))); + py=int(floor(ly - (0.5 * h))); + label_ext.init( floor(lx - 0.5 * w), floor(ly - 0.5 * h), ceil (lx + 0.5 * w), ceil (ly + 0.5 * h) ); + } + else + { // center image at reference location + px=int(floor(label_x - 0.5 * w)); + py=int(floor(label_y - 0.5 * h)); + label_ext.init( floor(label_x - 0.5 * w), floor(label_y - 0.5 * h), ceil (label_x + 0.5 * w), ceil (label_y + 0.5 * h)); + } + + if ( sym.get_allow_overlap() || detector_.has_placement(label_ext) ) + { + render_marker(feature,pixmap_.get_step(),px,py,**marker,tr,sym.get_opacity()); + + box2d dim = ren.prepare_glyphs(&text_placement.placements[0]); + ren.render_id(feature.id(),x,y,2); + detector_.insert(label_ext); + finder.update_detector(text_placement); + } + } + } + } + + else if (geom.num_points() > 1 && how_placed == LINE_PLACEMENT) + { + placement text_placement(info, sym, placement_options, scale_factor_, w, h, true); + + text_placement.avoid_edges = sym.get_avoid_edges(); + finder.find_point_placements(text_placement,path); + + position const& pos = sym.get_displacement(); + for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii) + { + placement_found= true; + double x = floor(text_placement.placements[ii].starting_x); + double y = floor(text_placement.placements[ii].starting_y); + + double lx = x - boost::get<0>(pos); + double ly = y - boost::get<1>(pos); + int px=int(floor(lx - (0.5*w))); + int py=int(floor(ly - (0.5*h))); + + render_marker(feature,pixmap_.get_step(),px,py,**marker,tr,sym.get_opacity()); + + box2d dim = ren.prepare_glyphs(&text_placement.placements[ii]); + ren.render_id(feature.id(),x,y,2); + } + finder.update_detector(text_placement); + } + } + } + } + } + if (placement_found) + pixmap_.add_feature(feature); + +} + +template void grid_renderer::process(shield_symbolizer const&, + Feature const&, + proj_transform const&); + +} diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp new file mode 100644 index 000000000..8201232b6 --- /dev/null +++ b/src/grid/process_text_symbolizer.cpp @@ -0,0 +1,156 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +// mapnik +#include +#include + +namespace mapnik { + +template +void grid_renderer::process(text_symbolizer const& sym, + Feature const& feature, + proj_transform const& prj_trans) +{ + typedef coord_transform2 path_type; + + bool placement_found = false; + text_placement_info_ptr placement_options = sym.get_placement_options()->get_placement_info(); + while (!placement_found && placement_options->next()) + { + expression_ptr name_expr = sym.get_name(); + if (!name_expr) return; + value_type result = boost::apply_visitor(evaluate(feature),*name_expr); + UnicodeString text = result.to_unicode(); + + if ( sym.get_text_transform() == UPPERCASE) + { + text = text.toUpper(); + } + else if ( sym.get_text_transform() == LOWERCASE) + { + text = text.toLower(); + } + else if ( sym.get_text_transform() == CAPITALIZE) + { + text = text.toTitle(NULL); + } + + if ( text.length() <= 0 ) continue; + color const& fill = sym.get_fill(); + + face_set_ptr faces; + + if (sym.get_fontset().size() > 0) + { + faces = font_manager_.get_face_set(sym.get_fontset()); + } + else + { + faces = font_manager_.get_face_set(sym.get_face_name()); + } + + stroker_ptr strk = font_manager_.get_stroker(); + if (!(faces->size() > 0 && strk)) + { + throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'"); + } + text_renderer ren(pixmap_, faces, *strk); + ren.set_pixel_size(placement_options->text_size * (scale_factor_ * (1.0/pixmap_.get_step()))); + ren.set_fill(fill); + ren.set_halo_fill(sym.get_halo_fill()); + ren.set_halo_radius(sym.get_halo_radius() * scale_factor_); + ren.set_opacity(sym.get_text_opacity()); + + // /pixmap_.get_step() ? + box2d dims(0,0,width_,height_); + placement_finder finder(detector_,dims); + + string_info info(text); + + faces->get_string_info(info); + unsigned num_geom = feature.num_geometries(); + for (unsigned i=0; inext_position_only()) + { + placement text_placement(info, sym, placement_options, scale_factor_); + text_placement.avoid_edges = sym.get_avoid_edges(); + if (sym.get_label_placement() == POINT_PLACEMENT || + sym.get_label_placement() == INTERIOR_PLACEMENT) + { + double label_x, label_y, z=0.0; + if (sym.get_label_placement() == POINT_PLACEMENT) + geom.label_position(&label_x, &label_y); + else + geom.label_interior_position(&label_x, &label_y); + prj_trans.backward(label_x,label_y, z); + t_.forward(&label_x,&label_y); + + double angle = 0.0; + expression_ptr angle_expr = sym.get_orientation(); + if (angle_expr) + { + // apply rotation + value_type result = boost::apply_visitor(evaluate(feature),*angle_expr); + angle = result.to_double(); + } + + finder.find_point_placement(text_placement,label_x,label_y, + angle, sym.get_vertical_alignment(),sym.get_line_spacing(), + sym.get_character_spacing(),sym.get_horizontal_alignment(), + sym.get_justify_alignment()); + + finder.update_detector(text_placement); + } + else if ( geom.num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT) + { + path_type path(t_,geom,prj_trans); + finder.find_line_placements(text_placement,path); + } + + if (!text_placement.placements.size()) continue; + placement_found = true; + + for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii) + { + double x = text_placement.placements[ii].starting_x; + double y = text_placement.placements[ii].starting_y; + ren.prepare_glyphs(&text_placement.placements[ii]); + ren.render_id(feature.id(),x,y,2); + } + } + } + } + if (placement_found) + pixmap_.add_feature(feature); +} + +template void grid_renderer::process(text_symbolizer const&, + Feature const&, + proj_transform const&); + +} +