add grid_renderer backend

This commit is contained in:
Dane Springmeyer 2011-04-26 21:44:52 +00:00
parent 6d7ca1ac6f
commit 5eea164b5a
24 changed files with 3094 additions and 33 deletions

View file

@ -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

View file

@ -25,6 +25,8 @@
// Windows DLL support
#define MAPNIK_SUPPORTS_GRID_RENDERER
#ifdef _WINDOWS
# define MAPNIK_EXP __declspec (dllexport)
# define MAPNIK_IMP __declspec (dllimport)

View file

@ -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<std::string>& names)
{
Processor & p = static_cast<Processor&>(*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,

View file

@ -54,6 +54,7 @@ extern "C"
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
// icu
#include <unicode/ubidi.h>
@ -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<FT_Pos>(x0 * (1 << 6));
start.y = static_cast<FT_Pos>((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;i<x_max;++i,++p)
{
for (j=y,q=0;j<y_max;++j,++q)
{
int gray=bitmap->buffer[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_;

View file

@ -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 <mapnik/image_data.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/image_view.hpp>
#include <mapnik/global.hpp>
#include <mapnik/value.hpp>
// stl
#include <map>
#include <cmath>
#include <string>
#include <cassert>
#include <vector>
namespace mapnik
{
template <typename T>
class MAPNIK_DECL hit_grid
{
public:
typedef T value_type;
typedef mapnik::ImageData<value_type> data_type;
typedef std::string lookup_type;
// mapping between pixel id and join_field
typedef std::map<value_type, lookup_type> feature_key_type;
typedef std::map<lookup_type, value_type> key_type;
typedef std::map<std::string, mapnik::value> feature_properties_type;
// note: feature_type is not the same as a mapnik::Feature as it lacks a geometry
typedef std::map<std::string, feature_properties_type > feature_type;
private:
unsigned width_;
unsigned height_;
std::string join_field_;
key_type keys_;
std::vector<std::string> key_order_;
feature_key_type f_keys_;
feature_type features_;
data_type data_;
std::set<std::string> 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<T>& 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<std::string,value> 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<std::string,value>::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<std::string> 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<data_type> get_view(unsigned x,unsigned y, unsigned w,unsigned h)
{
return image_view<data_type>(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<int> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height());
if (ext0.intersects(ext1))
{
box2d<int> 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<uint16_t> grid;
}
#endif //MAPNIK_GRID_HPP

View file

@ -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

View file

@ -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 <string.h>
#include "agg_basics.h"
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid_rendering_buffer.hpp>
namespace mapnik
{
//============================================================blender_gray
template<class ColorT> 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 ColorT, class GammaLut> 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 ColorT, class GammaLut> 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 Blender, class RenBuf, unsigned Step=1, unsigned Offset=0>
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<class PixFmt>
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<class Function> 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<class GammaLut> void apply_gamma_dir(const GammaLut& g)
{
for_each_pixel(apply_gamma_dir_gray<color_type, GammaLut>(g));
}
//--------------------------------------------------------------------
template<class GammaLut> void apply_gamma_inv(const GammaLut& g)
{
for_each_pixel(apply_gamma_inv_gray<color_type, GammaLut>(g));
}
//--------------------------------------------------------------------
template<class RenBuf2>
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<class SrcPixelFormatRenderer>
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<class SrcPixelFormatRenderer>
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<gray16> blender_gray16;
typedef pixfmt_alpha_blend_gray<blender_gray16,
mapnik::grid_rendering_buffer> pixfmt_gray16; //----pixfmt_gray16
}
#endif

View file

@ -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 <boost/utility.hpp>
#include "agg_rasterizer_scanline_aa.h"
namespace mapnik {
struct grid_rasterizer : agg::rasterizer_scanline_aa<>, boost::noncopyable {};
}
#endif //MAPNIK_AGG_RASTERIZER_HPP

View file

@ -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 <mapnik/config.hpp>
#include <mapnik/feature_style_processor.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/map.hpp>
//#include <mapnik/marker.hpp>
#include <mapnik/grid/grid.hpp>
// boost
#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
// 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 <typename T>
class MAPNIK_DECL grid_renderer : public feature_style_processor<grid_renderer<T> >,
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<freetype_engine> font_manager_;
label_collision_detector4 detector_;
boost::scoped_ptr<grid_rasterizer> ras_ptr;
};
}
#endif //GRID_RENDERER_HPP

View file

@ -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 <mapnik/grid/grid.hpp>
#include "agg_rendering_buffer.h"
namespace mapnik {
typedef agg::row_ptr_cache<mapnik::grid::value_type> grid_rendering_buffer;
}
#endif //MAPNIK_AGG_RASTERIZER_HPP

View file

@ -26,6 +26,7 @@
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/gradient.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <boost/utility.hpp>
@ -343,6 +344,93 @@ public:
}
}
template <typename Rasterizer, typename Scanline, typename Renderer>
void render_id(Rasterizer& ras,
Scanline& sl,
Renderer& ren,
int feature_id,
agg::trans_affine const& mtx,
double opacity,
const box2d<double> &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<double> 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_;

View file

@ -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,7 +166,7 @@ if env['JPEG']:
jpeg_reader.cpp
""")
if True : # agg backend
# agg backend
source += Split(
"""
agg/agg_renderer.cpp
@ -177,14 +181,47 @@ 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
try:
@ -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)

162
src/grid/grid_renderer.cpp Normal file
View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/font_set.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/text_path.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/svg/svg_renderer.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
// boost
#include <boost/utility.hpp>
// stl
#ifdef MAPNIK_DEBUG
#include <iostream>
#endif
//#include <cmath>
namespace mapnik
{
template <typename T>
grid_renderer<T>::grid_renderer(Map const& m, T & pixmap, double scale_factor, unsigned offset_x, unsigned offset_y)
: feature_style_processor<grid_renderer>(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<double>(-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 <typename T>
grid_renderer<T>::~grid_renderer() {}
template <typename T>
void grid_renderer<T>::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 <typename T>
void grid_renderer<T>::end_map_processing(Map const& )
{
#ifdef MAPNIK_DEBUG
std::clog << "end map processing\n";
#endif
}
template <typename T>
void grid_renderer<T>::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 <typename T>
void grid_renderer<T>::end_layer_processing(layer const&)
{
#ifdef MAPNIK_DEBUG
std::clog << "end layer processing\n";
#endif
}
template <typename T>
void grid_renderer<T>::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<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<mapnik::pixfmt_gray16> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> 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<double> const& bbox = (*marker.get_vector_data())->bounding_box();
coord<double,2> 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<svg_path_storage> stl_storage((*marker.get_vector_data())->source());
svg_path_adapter svg_path(stl_storage);
svg_renderer<svg_path_adapter,
agg::pod_bvector<path_attributes>, 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<grid>;
}

View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/segment.hpp>
// boost
#include <boost/scoped_ptr.hpp>
// 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 <typename T>
void grid_renderer<T>::process(building_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<mapnik::pixfmt_gray16> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> 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<feature.num_geometries();++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (geom.num_points() > 2)
{
boost::scoped_ptr<geometry_type> frame(new geometry_type(LineString));
boost::scoped_ptr<geometry_type> roof(new geometry_type(Polygon));
std::deque<segment_t> face_segments;
double x0(0);
double y0(0);
unsigned cm = geom.vertex(&x0,&y0);
for (unsigned j=1;j<geom.num_points();++j)
{
double x(0);
double y(0);
cm = geom.vertex(&x,&y);
if (cm == SEG_MOVETO)
{
frame->move_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<segment_t>::const_iterator itr=face_segments.begin();
for (;itr!=face_segments.end();++itr)
{
boost::scoped_ptr<geometry_type> 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;j<geom.num_points();++j)
{
double x,y;
unsigned cm = geom.vertex(&x,&y);
if (cm == SEG_MOVETO)
{
frame->move_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<path_type> 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<grid>::process(building_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_renderer.hpp>
#include <iostream>
namespace mapnik {
template <typename T>
void grid_renderer<T>::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<grid>::process(glyph_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
// 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 <string>
namespace mapnik {
template <typename T>
void grid_renderer<T>::process(line_pattern_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<mapnik::pixfmt_gray16> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> 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<feature.num_geometries();++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (geom.num_points() > 1)
{
path_type path(t_,geom,prj_trans);
agg::conv_stroke<path_type> 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<grid>::process(line_pattern_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
// 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 <string>
namespace mapnik {
template <typename T>
void grid_renderer<T>::process(line_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<mapnik::pixfmt_gray16> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> 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<feature.num_geometries();++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (geom.num_points() > 1)
{
path_type path(t_,geom,prj_trans);
if (stroke_.has_dash())
{
agg::conv_dash<path_type> 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<agg::conv_dash<path_type > > 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<path_type> 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<grid>::process(line_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/svg/svg_renderer.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/markers_placement.hpp>
#include <mapnik/arrow.hpp>
// 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 <algorithm>
namespace mapnik {
template <typename T>
void grid_renderer<T>::process(markers_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<mapnik::pixfmt_gray16> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> 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<double,6> 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<marker_ptr> mark = mapnik::marker_cache::instance()->find(filename, true);
if (mark && *mark && (*mark)->is_vector())
{
boost::optional<path_ptr> marker = (*mark)->get_vector_data();
box2d<double> 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<double> extent(x1,y1,x2,y2);
using namespace mapnik::svg;
vertex_stl_adapter<svg_path_storage> stl_storage((*marker)->source());
svg_path_adapter svg_path(stl_storage);
svg_renderer<svg_path_adapter,
agg::pod_bvector<path_attributes>, mapnik::pixfmt_gray16 > svg_renderer(svg_path,(*marker)->attributes());
bool placed = false;
for (unsigned i=0; i<feature.num_geometries(); ++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (geom.num_points() <= 1)
{
std::clog << "### Warning svg markers not supported yet for points within markers_symbolizer\n";
continue;
}
path_type path(t_,geom,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
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<double>(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<double> extent;
double dx = w + (2*strk_width);
double dy = h + (2*strk_width);
if (marker_type == ARROW)
{
extent = arrow_.extent();
double x1 = extent.minx();
double y1 = extent.miny();
double x2 = extent.maxx();
double y2 = extent.maxy();
tr.transform(&x1,&y1);
tr.transform(&x2,&y2);
extent.init(x1,y1,x2,y2);
}
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<feature.num_geometries(); ++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1)
{
geom.label_position(&x,&y);
prj_trans.backward(x,y,z);
t_.forward(&x,&y);
int px = int(floor(x - 0.5 * dx));
int py = int(floor(y - 0.5 * dy));
box2d<double> label_ext (px, py, px + dx +1, py + dy +1);
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
{
agg::ellipse c(x, y, w, h);
agg::path_storage marker;
marker.concat_path(c);
ras_ptr->add_path(marker);
// outline
if (strk_width)
{
agg::conv_stroke<agg::path_storage> 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<path_type, label_collision_detector4> placement(path, extent, detector_,
sym.get_spacing() * scale_factor_,
sym.get_max_error(),
sym.get_allow_overlap());
double x_t, y_t, angle;
while (placement.get_point(&x_t, &y_t, &angle))
{
agg::trans_affine matrix;
if (marker_type == ELLIPSE)
{
// todo proper bbox - this is buggy
agg::ellipse c(x_t, y_t, w, h);
marker.concat_path(c);
agg::trans_affine matrix;
matrix *= agg::trans_affine_translation(-x_t,-y_t);
matrix *= agg::trans_affine_rotation(angle);
matrix *= agg::trans_affine_translation(x_t,y_t);
marker.transform(matrix);
}
else
{
matrix = tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x_t, y_t);
}
agg::conv_transform<agg::path_storage, agg::trans_affine> trans(marker, matrix);
// fill
ras_ptr->add_path(trans);
// outline
if (strk_width)
{
agg::conv_stroke<agg::conv_transform<agg::path_storage, agg::trans_affine> > outline(trans);
outline.generator().width(strk_width * scale_factor_);
ras_ptr->add_path(outline);
}
}
}
}
ren.color(mapnik::gray16(feature.id()));
agg::render_scanlines(*ras_ptr, sl, ren);
pixmap_.add_feature(feature);
}
}
template void grid_renderer<grid>::process(markers_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/marker_cache.hpp>
// stl
#include <string>
namespace mapnik {
template <typename T>
void grid_renderer<T>::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<mapnik::marker_ptr> marker;
if ( !filename.empty() )
{
marker = marker_cache::instance()->find(filename, true);
}
else
{
marker.reset(boost::shared_ptr<mapnik::marker> (new mapnik::marker()));
}
if (marker)
{
for (unsigned i=0; i<feature.num_geometries(); ++i)
{
geometry_type const& geom = feature.get_geometry(i);
double x;
double y;
double z=0;
if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT)
geom.label_position(&x, &y);
else
geom.label_interior_position(&x, &y);
prj_trans.backward(x,y,z);
t_.forward(&x,&y);
int w = (*marker)->width();
int h = (*marker)->height();
int px = int(floor(x - 0.5 * w));
int py = int(floor(y - 0.5 * h));
box2d<double> label_ext (px, py, px + w, py + h);
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
{
agg::trans_affine tr;
boost::array<double,6> 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<grid>::process(point_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
// agg
#include "agg_rasterizer_scanline_aa.h"
#include "agg_renderer_scanline.h"
#include "agg_scanline_u.h"
// stl
#include <string>
#include <map>
namespace mapnik {
template <typename T>
void grid_renderer<T>::process(polygon_pattern_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<mapnik::pixfmt_gray16> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> 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<feature.num_geometries();++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (geom.num_points() > 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<grid>::process(polygon_pattern_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
// agg
#include "agg_rasterizer_scanline_aa.h"
#include "agg_renderer_scanline.h"
#include "agg_scanline_u.h"
// stl
#include <string>
#include <map>
namespace mapnik {
template <typename T>
void grid_renderer<T>::process(polygon_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<mapnik::pixfmt_gray16> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> 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<feature.num_geometries();++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (geom.num_points() > 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<grid>::process(polygon_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_renderer.hpp>
namespace mapnik {
template <typename T>
void grid_renderer<T>::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<grid>::process(raster_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/svg/svg_renderer.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
// agg
#include "agg_rasterizer_scanline_aa.h"
#include "agg_renderer_scanline.h"
#include "agg_scanline_u.h"
namespace mapnik {
template <typename T>
void grid_renderer<T>::process(shield_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> 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,value_type>(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<double,6> 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<mapnik::marker_ptr> marker;
if ( !filename.empty() )
{
marker = marker_cache::instance()->find(filename, true);
}
else
{
marker.reset(boost::shared_ptr<mapnik::marker> (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<T> 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<label_collision_detector4> 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<double> 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<double> 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<path_type>(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<double> 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<grid>::process(shield_symbolizer const&,
Feature const&,
proj_transform const&);
}

View file

@ -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 <mapnik/grid/grid_renderer.hpp>
#include <mapnik/font_engine_freetype.hpp>
namespace mapnik {
template <typename T>
void grid_renderer<T>::process(text_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry_type> 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,value_type>(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<T> 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<double> dims(0,0,width_,height_);
placement_finder<label_collision_detector4> finder(detector_,dims);
string_info info(text);
faces->get_string_info(info);
unsigned num_geom = feature.num_geometries();
for (unsigned i=0; i<num_geom; ++i)
{
geometry_type const& geom = feature.get_geometry(i);
if (geom.num_points() == 0) continue; // don't bother with empty geometries
while (!placement_found && placement_options->next_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,value_type>(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<path_type>(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<grid>::process(text_symbolizer const&,
Feature const&,
proj_transform const&);
}