root/trunk/src/agg_renderer.cpp

Revision 1685, 29.9 kB (checked in by alberto, 2 days ago)

pre-eliminary raster coloring support

Line 
1/*****************************************************************************
2 *
3 * This file is part of Mapnik (c++ mapping toolkit)
4 *
5 * Copyright (C) 2006 Artem Pavlenko
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 *
21 *****************************************************************************/
22//$Id$
23
24// mapnik
25#include <mapnik/agg_renderer.hpp>
26#include <mapnik/image_util.hpp>
27#include <mapnik/image_cache.hpp>
28#include <mapnik/unicode.hpp>
29#include <mapnik/placement_finder.hpp>
30#include <mapnik/markers_converter.hpp>
31#include <mapnik/arrow.hpp>
32#include <mapnik/config_error.hpp>
33#include <mapnik/font_set.hpp>
34#include <mapnik/path_expression_grammar.hpp>
35
36// agg
37#define AGG_RENDERING_BUFFER row_ptr_cache<int8u>
38#include "agg_rendering_buffer.h"
39#include "agg_pixfmt_rgba.h"
40#include "agg_rasterizer_scanline_aa.h"
41#include "agg_basics.h"
42#include "agg_scanline_p.h"
43#include "agg_scanline_u.h"
44#include "agg_renderer_scanline.h"
45#include "agg_path_storage.h"
46#include "agg_span_allocator.h"
47#include "agg_span_pattern_rgba.h"
48#include "agg_image_accessors.h"
49#include "agg_conv_stroke.h"
50#include "agg_conv_dash.h"
51#include "agg_conv_contour.h"
52#include "agg_conv_clip_polyline.h"
53#include "agg_vcgen_stroke.h"
54#include "agg_conv_adaptor_vcgen.h"
55#include "agg_conv_smooth_poly1.h"
56#include "agg_conv_marker.h"
57#include "agg_vcgen_markers_term.h"
58#include "agg_renderer_outline_aa.h"
59#include "agg_rasterizer_outline_aa.h"
60#include "agg_rasterizer_outline.h"
61#include "agg_renderer_outline_image.h"
62#include "agg_span_allocator.h"
63#include "agg_span_pattern_rgba.h"
64#include "agg_renderer_scanline.h"
65#include "agg_pattern_filters_rgba.h"
66#include "agg_renderer_outline_image.h"
67#include "agg_vpgen_clip_polyline.h"
68#include "agg_arrowhead.h"
69
70// boost
71#include <boost/utility.hpp>
72#include <boost/tuple/tuple.hpp>
73
74// stl
75#ifdef MAPNIK_DEBUG
76#include <iostream>
77#endif
78
79#include <cmath>
80
81namespace mapnik
82{
83class pattern_source : private boost::noncopyable
84{
85public:
86    pattern_source(image_data_32 const& pattern)
87        : pattern_(pattern) {}
88
89    unsigned int width() const
90    {
91        return pattern_.width();
92    }
93    unsigned int height() const
94    {
95        return pattern_.height();
96    }
97    agg::rgba8 pixel(int x, int y) const
98    {
99        unsigned c = pattern_(x,y);
100        return agg::rgba8(c & 0xff,
101                          (c >> 8) & 0xff,
102                          (c >> 16) & 0xff,
103                          (c >> 24) & 0xff);
104    }
105private:
106    image_data_32 const& pattern_;
107};
108
109struct rasterizer :  agg::rasterizer_scanline_aa<>, boost::noncopyable {};
110
111template <typename T>
112agg_renderer<T>::agg_renderer(Map const& m, T & pixmap, unsigned offset_x, unsigned offset_y)
113    : feature_style_processor<agg_renderer>(m),
114      pixmap_(pixmap),
115      width_(pixmap_.width()),
116      height_(pixmap_.height()),
117      t_(m.getWidth(),m.getHeight(),m.getCurrentExtent(),offset_x,offset_y),
118      font_engine_(),
119      font_manager_(font_engine_),
120      detector_(box2d<double>(-m.buffer_size(), -m.buffer_size(), m.getWidth() + m.buffer_size() ,m.getHeight() + m.buffer_size())),
121      ras_ptr(new rasterizer)
122{
123    boost::optional<color> bg = m.background();
124    if (bg) pixmap_.set_background(*bg);
125#ifdef MAPNIK_DEBUG
126    std::clog << "scale=" << m.scale() << "\n";
127#endif
128}
129
130template <typename T>
131agg_renderer<T>::~agg_renderer() {}
132
133template <typename T>
134void agg_renderer<T>::start_map_processing(Map const& map)
135{
136#ifdef MAPNIK_DEBUG
137    std::clog << "start map processing bbox="
138              << map.getCurrentExtent() << "\n";
139#endif
140    ras_ptr->clip_box(0,0,width_,height_);
141}
142
143template <typename T>
144void agg_renderer<T>::end_map_processing(Map const& )
145{
146#ifdef MAPNIK_DEBUG
147    std::clog << "end map processing\n";
148#endif
149}
150
151template <typename T>
152void agg_renderer<T>::start_layer_processing(layer const& lay)
153{
154#ifdef MAPNIK_DEBUG
155    std::clog << "start layer processing : " << lay.name()  << "\n";
156    std::clog << "datasource = " << lay.datasource().get() << "\n";
157#endif
158    if (lay.clear_label_cache())
159    {
160        detector_.clear();
161    }
162}
163
164template <typename T>
165void agg_renderer<T>::end_layer_processing(layer const&)
166{
167#ifdef MAPNIK_DEBUG
168    std::clog << "end layer processing\n";
169#endif
170}
171
172template <typename T>
173void agg_renderer<T>::process(polygon_symbolizer const& sym,
174                              Feature const& feature,
175                              proj_transform const& prj_trans)
176{
177    typedef  coord_transform2<CoordTransform,geometry2d> path_type;
178    typedef agg::renderer_base<agg::pixfmt_rgba32_plain> ren_base;
179    typedef agg::renderer_scanline_aa_solid<ren_base> renderer;
180
181    color const& fill_ = sym.get_fill();
182    agg::scanline_u8 sl;
183
184    agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4);
185    agg::pixfmt_rgba32_plain pixf(buf);
186
187    ren_base renb(pixf);
188    unsigned r=fill_.red();
189    unsigned g=fill_.green();
190    unsigned b=fill_.blue();
191    unsigned a=fill_.alpha();
192    renderer ren(renb);
193
194    ras_ptr->reset();
195    ras_ptr->gamma(agg::gamma_linear(0.0, sym.get_gamma()));
196
197    for (unsigned i=0;i<feature.num_geometries();++i)
198    {
199        geometry2d const& geom=feature.get_geometry(i);
200        if (geom.num_points() > 2)
201        {
202            path_type path(t_,geom,prj_trans);
203            ras_ptr->add_path(path);
204        }
205    }
206    ren.color(agg::rgba8(r, g, b, int(a * sym.get_opacity())));
207    agg::render_scanlines(*ras_ptr, sl, ren);
208}
209
210typedef boost::tuple<double,double,double,double> segment_t;
211bool y_order(segment_t const& first,segment_t const& second)
212{
213    double miny0 = std::min(first.get<1>(),first.get<3>());
214    double miny1 = std::min(second.get<1>(),second.get<3>());
215    return  miny0 > miny1;
216}
217
218template <typename T>
219void agg_renderer<T>::process(building_symbolizer const& sym,
220                              Feature const& feature,
221                              proj_transform const& prj_trans)
222{
223    typedef  coord_transform2<CoordTransform,geometry2d> path_type;
224    typedef  coord_transform3<CoordTransform,geometry2d> path_type_roof;
225    typedef agg::renderer_base<agg::pixfmt_rgba32_plain> ren_base;
226    typedef agg::renderer_scanline_aa_solid<ren_base> renderer;
227
228    agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4);
229    agg::pixfmt_rgba32_plain pixf(buf);
230    ren_base renb(pixf);
231
232    color const& fill_  = sym.get_fill();
233    unsigned r=fill_.red();
234    unsigned g=fill_.green();
235    unsigned b=fill_.blue();
236    unsigned a=fill_.alpha();
237    renderer ren(renb);
238    agg::scanline_u8 sl;
239
240    ras_ptr->reset();
241    ras_ptr->gamma(agg::gamma_linear());
242   
243    double height = 0.7071 * sym.height(); // height in meters
244
245    for (unsigned i=0;i<feature.num_geometries();++i)
246    {
247        geometry2d const& geom = feature.get_geometry(i);
248        if (geom.num_points() > 2)
249        {
250            boost::scoped_ptr<geometry2d> frame(new line_string_impl);
251            boost::scoped_ptr<geometry2d> roof(new polygon_impl);
252            std::deque<segment_t> face_segments;
253            double x0(0);
254            double y0(0);
255            unsigned cm = geom.vertex(&x0,&y0);
256            for (unsigned j=1;j<geom.num_points();++j)
257            {
258                double x,y;
259                cm = geom.vertex(&x,&y);
260                if (cm == SEG_MOVETO)
261                {
262                    frame->move_to(x,y);
263                }
264                else if (cm == SEG_LINETO)
265                {
266                    frame->line_to(x,y);
267                }
268                if (j!=0)
269                {
270                    face_segments.push_back(segment_t(x0,y0,x,y));
271                }
272                x0 = x;
273                y0 = y;
274            }
275            std::sort(face_segments.begin(),face_segments.end(), y_order);
276            std::deque<segment_t>::const_iterator itr=face_segments.begin();
277            for (;itr!=face_segments.end();++itr)
278            {
279                boost::scoped_ptr<geometry2d> faces(new polygon_impl);
280                faces->move_to(itr->get<0>(),itr->get<1>());
281                faces->line_to(itr->get<2>(),itr->get<3>());
282                faces->line_to(itr->get<2>(),itr->get<3>() + height);
283                faces->line_to(itr->get<0>(),itr->get<1>() + height);
284
285                path_type faces_path (t_,*faces,prj_trans);
286                ras_ptr->add_path(faces_path);
287                ren.color(agg::rgba8(int(r*0.8), int(g*0.8), int(b*0.8), int(a * sym.get_opacity())));
288                agg::render_scanlines(*ras_ptr, sl, ren);
289                ras_ptr->reset();
290
291                frame->move_to(itr->get<0>(),itr->get<1>());
292                frame->line_to(itr->get<0>(),itr->get<1>()+height);
293            }
294
295            geom.rewind(0);
296            for (unsigned j=0;j<geom.num_points();++j)
297            {
298                double x,y;
299                unsigned cm = geom.vertex(&x,&y);
300                if (cm == SEG_MOVETO)
301                {
302                    frame->move_to(x,y+height);
303                    roof->move_to(x,y+height);
304                }
305                else if (cm == SEG_LINETO)
306                {
307                    frame->line_to(x,y+height);
308                    roof->line_to(x,y+height);
309                }
310            }
311            path_type path(t_,*frame,prj_trans);
312            agg::conv_stroke<path_type>  stroke(path);
313            ras_ptr->add_path(stroke);
314            ren.color(agg::rgba8(128, 128, 128, int(255 * sym.get_opacity())));
315            agg::render_scanlines(*ras_ptr, sl, ren);
316            ras_ptr->reset();
317
318            path_type roof_path (t_,*roof,prj_trans);
319            ras_ptr->add_path(roof_path);
320            ren.color(agg::rgba8(r, g, b, int(a * sym.get_opacity())));
321            agg::render_scanlines(*ras_ptr, sl, ren);
322        }
323    }
324}
325
326template <typename T>
327void agg_renderer<T>::process(line_symbolizer const& sym,
328                              Feature const& feature,
329                              proj_transform const& prj_trans)
330{
331    typedef agg::renderer_base<agg::pixfmt_rgba32_plain> ren_base;
332    typedef coord_transform2<CoordTransform,geometry2d> path_type;
333    typedef agg::renderer_outline_aa<ren_base> renderer_oaa;
334    typedef agg::rasterizer_outline_aa<renderer_oaa> rasterizer_outline_aa;
335    typedef agg::renderer_scanline_aa_solid<ren_base> renderer;
336
337    agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4);
338    agg::pixfmt_rgba32_plain pixf(buf);
339
340    ren_base renb(pixf);
341    mapnik::stroke const&  stroke_ = sym.get_stroke();
342    color const& col = stroke_.get_color();
343    unsigned r=col.red();
344    unsigned g=col.green();
345    unsigned b=col.blue();
346    unsigned a=col.alpha();
347    renderer ren(renb);
348    ras_ptr->reset();
349    ras_ptr->gamma(agg::gamma_linear());
350
351    agg::scanline_p8 sl;
352
353    for (unsigned i=0;i<feature.num_geometries();++i)
354    {
355        geometry2d const& geom = feature.get_geometry(i);
356        if (geom.num_points() > 1)
357        {
358            path_type path(t_,geom,prj_trans);
359
360            if (stroke_.has_dash())
361            {
362                agg::conv_dash<path_type> dash(path);
363                dash_array const& d = stroke_.get_dash_array();
364                dash_array::const_iterator itr = d.begin();
365                dash_array::const_iterator end = d.end();
366                for (;itr != end;++itr)
367                {
368                    dash.add_dash(itr->first, itr->second);
369                }
370
371                agg::conv_stroke<agg::conv_dash<path_type > > stroke(dash);
372
373                line_join_e join=stroke_.get_line_join();
374                if ( join == MITER_JOIN)
375                    stroke.generator().line_join(agg::miter_join);
376                else if( join == MITER_REVERT_JOIN)
377                    stroke.generator().line_join(agg::miter_join);
378                else if( join == ROUND_JOIN)
379                    stroke.generator().line_join(agg::round_join);
380                else
381                    stroke.generator().line_join(agg::bevel_join);
382
383                line_cap_e cap=stroke_.get_line_cap();
384                if (cap == BUTT_CAP)
385                    stroke.generator().line_cap(agg::butt_cap);
386                else if (cap == SQUARE_CAP)
387                    stroke.generator().line_cap(agg::square_cap);
388                else
389                    stroke.generator().line_cap(agg::round_cap);
390
391                stroke.generator().miter_limit(4.0);
392                stroke.generator().width(stroke_.get_width());
393
394                ras_ptr->add_path(stroke);
395
396            }
397            else
398            {
399                agg::conv_stroke<path_type>  stroke(path);
400                line_join_e join=stroke_.get_line_join();
401                if ( join == MITER_JOIN)
402                    stroke.generator().line_join(agg::miter_join);
403                else if( join == MITER_REVERT_JOIN)
404                    stroke.generator().line_join(agg::miter_join);
405                else if( join == ROUND_JOIN)
406                    stroke.generator().line_join(agg::round_join);
407                else
408                    stroke.generator().line_join(agg::bevel_join);
409
410                line_cap_e cap=stroke_.get_line_cap();
411                if (cap == BUTT_CAP)
412                    stroke.generator().line_cap(agg::butt_cap);
413                else if (cap == SQUARE_CAP)
414                    stroke.generator().line_cap(agg::square_cap);
415                else
416                    stroke.generator().line_cap(agg::round_cap);
417
418                stroke.generator().miter_limit(4.0);
419                stroke.generator().width(stroke_.get_width());
420                ras_ptr->add_path(stroke);
421            }
422        }
423    }
424    ren.color(agg::rgba8(r, g, b, int(a*stroke_.get_opacity())));
425    agg::render_scanlines(*ras_ptr, sl, ren);
426}
427
428template <typename T>
429void agg_renderer<T>::process(point_symbolizer const& sym,
430                              Feature const& feature,
431                              proj_transform const& prj_trans)
432{
433    double x;
434    double y;
435    double z=0;
436   
437    std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
438    boost::optional<mapnik::image_ptr> data;
439   
440    if ( filename.empty() )
441    {
442        // default OGC 4x4 black pixel
443        data = boost::optional<mapnik::image_ptr>(new image_data_32(4,4));
444        (*data)->set(0xff000000);
445    }
446    else
447    {
448        data = mapnik::image_cache::instance()->find(filename,true);
449    }
450
451    if ( data )
452    {
453        for (unsigned i=0;i<feature.num_geometries();++i)
454        {
455            geometry2d const& geom = feature.get_geometry(i);
456
457            geom.label_position(&x,&y);
458            prj_trans.backward(x,y,z);
459            t_.forward(&x,&y);
460            int w = (*data)->width();
461            int h = (*data)->height();
462            int px=int(floor(x - 0.5 * w));
463            int py=int(floor(y - 0.5 * h));
464            box2d<double> label_ext (floor(x - 0.5 * w),
465                                     floor(y - 0.5 * h),
466                                     ceil (x + 0.5 * w),
467                                     ceil (y + 0.5 * h));
468            if (sym.get_allow_overlap() ||
469                detector_.has_placement(label_ext))
470            {
471                pixmap_.set_rectangle_alpha2(*(*data),px,py,sym.get_opacity());
472                detector_.insert(label_ext);
473            }
474        }
475    }
476}
477
478template <typename T>
479void  agg_renderer<T>::process(shield_symbolizer const& sym,
480                               Feature const& feature,
481                               proj_transform const& prj_trans)
482{
483    typedef  coord_transform2<CoordTransform,geometry2d> path_type;
484
485    UnicodeString text;
486    if( sym.get_no_text() )
487        text = UnicodeString( " " );  // TODO: fix->use 'space' as the text to render
488    else
489    {
490        expression_ptr name_expr = sym.get_name();
491        if (!name_expr) return;
492        value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature),*name_expr);
493        text = result.to_unicode();
494    }
495   
496    if ( sym.get_text_convert() == TOUPPER)
497    {
498        text = text.toUpper();
499    }
500    else if ( sym.get_text_convert() == TOLOWER)
501    {
502        text = text.toLower();
503    }
504   
505    std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
506    boost::optional<mapnik::image_ptr> data = mapnik::image_cache::instance()->find(filename,true);
507   
508    if (text.length() > 0 && data)
509    {
510        face_set_ptr faces;
511
512        if (sym.get_fontset().size() > 0)
513        {
514            faces = font_manager_.get_face_set(sym.get_fontset());
515        }
516        else
517        {
518            faces = font_manager_.get_face_set(sym.get_face_name());
519        }
520
521        if (faces->size() > 0)
522        {
523            text_renderer<T> ren(pixmap_, faces);
524
525            ren.set_pixel_size(sym.get_text_size());
526            ren.set_fill(sym.get_fill());
527            ren.set_halo_fill(sym.get_halo_fill());
528            ren.set_halo_radius(sym.get_halo_radius());
529
530            placement_finder<label_collision_detector4> finder(detector_);
531
532            string_info info(text);
533
534            faces->get_string_info(info);
535
536
537            int w = (*data)->width();
538            int h = (*data)->height();
539
540            unsigned num_geom = feature.num_geometries();
541            for (unsigned i=0;i<num_geom;++i)
542            {
543                geometry2d const& geom = feature.get_geometry(i);
544                if (geom.num_points() > 0 )
545                {
546                    path_type path(t_,geom,prj_trans);
547
548                    label_placement_enum how_placed = sym.get_label_placement();
549                    if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT)
550                    {
551                        // for every vertex, try and place a shield/text
552                        geom.rewind(0);
553                        for( unsigned jj = 0; jj < geom.num_points(); jj++ )
554                        {
555                            double label_x;
556                            double label_y;
557                            double z=0.0;
558                            placement text_placement(info, sym, w, h, false);
559                            text_placement.avoid_edges = sym.get_avoid_edges();
560                            text_placement.allow_overlap = sym.get_allow_overlap();
561                            if( how_placed == VERTEX_PLACEMENT )
562                                geom.vertex(&label_x,&label_y);  // by vertex
563                            else
564                                geom.label_position(&label_x, &label_y);  // by middle of line or by point
565                            prj_trans.backward(label_x,label_y, z);
566                            t_.forward(&label_x,&label_y);
567
568                            finder.find_point_placement( text_placement,label_x,label_y,sym.get_vertical_alignment(),sym.get_line_spacing(),
569                                                         sym.get_character_spacing(),sym.get_horizontal_alignment(),sym.get_justify_alignment() );
570
571                            // check to see if image overlaps anything too, there is only ever 1 placement found for points and verticies
572                            if( text_placement.placements.size() > 0)
573                            {
574                                double x = text_placement.placements[0].starting_x;
575                                double y = text_placement.placements[0].starting_y;
576                                int px;
577                                int py;
578                                box2d<double> label_ext;
579
580                                if( !sym.get_unlock_image() )
581                                {  // center image at text center position
582                                    // remove displacement from image label
583                                    position pos = sym.get_displacement();
584                                    double lx = x - boost::get<0>(pos);
585                                    double ly = y - boost::get<1>(pos);
586                                    px=int(floor(lx - (0.5 * w))) ;
587                                    py=int(floor(ly - (0.5 * h))) ;
588                                    label_ext.init( floor(lx - 0.5 * w), floor(ly - 0.5 * h), ceil (lx + 0.5 * w), ceil (ly + 0.5 * h) );
589                                }
590                                else
591                                {  // center image at reference location
592                                    px=int(floor(label_x - 0.5 * w));
593                                    py=int(floor(label_y - 0.5 * h));
594                                    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));
595                                }
596
597                                if ( sym.get_allow_overlap() || detector_.has_placement(label_ext) )
598                                {
599                                    //pixmap_.set_rectangle_alpha(px,py,*data);
600                                    pixmap_.set_rectangle_alpha2(*(*data),px,py,float(sym.get_opacity()));
601                                    box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[0]);
602                                    ren.render(x,y);
603                                    detector_.insert(label_ext);
604                                    finder.update_detector(text_placement);
605                                }
606                            }
607                        }
608                    }
609
610                    else if (geom.num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT)
611                    {
612                        placement text_placement(info, sym, w, h, true);
613                        text_placement.avoid_edges = sym.get_avoid_edges();
614                        finder.find_point_placements<path_type>(text_placement,path);
615
616                        for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
617                        {
618                            int w = (*data)->width();
619                            int h = (*data)->height();
620                            double x = text_placement.placements[ii].starting_x;
621                            double y = text_placement.placements[ii].starting_y;
622                         
623                            int px=int(x - (w/2));
624                            int py=int(y - (h/2));
625                         
626                            pixmap_.set_rectangle_alpha(px,py,*(*data));
627                         
628                            box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
629                            ren.render(x,y);
630                        }
631                        finder.update_detector(text_placement);
632                    }
633                }
634            }
635        }
636    }
637}
638
639template <typename T>
640void  agg_renderer<T>::process(line_pattern_symbolizer const& sym,
641                               Feature const& feature,
642                               proj_transform const& prj_trans)
643{
644    typedef  coord_transform2<CoordTransform,geometry2d> path_type;
645    typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba8> pattern_type;
646    typedef agg::renderer_base<agg::pixfmt_rgba32_plain> renderer_base;
647    typedef agg::renderer_outline_image<renderer_base, pattern_type> renderer_type;
648    typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type;
649
650    agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4);
651    agg::pixfmt_rgba32_plain pixf(buf);
652   
653    std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
654    boost::optional<mapnik::image_ptr> pat = mapnik::image_cache::instance()->find(filename,true);
655
656    if (!pat) return;
657     
658    renderer_base ren_base(pixf);
659    agg::pattern_filter_bilinear_rgba8 filter;
660    pattern_source source(*(*pat));
661    pattern_type pattern (filter,source);
662    renderer_type ren(ren_base, pattern);
663    ren.clip_box(0,0,width_,height_);
664    rasterizer_type ras(ren);
665
666    for (unsigned i=0;i<feature.num_geometries();++i)
667    {
668        geometry2d const& geom = feature.get_geometry(i);
669        if (geom.num_points() > 1)
670        {
671            path_type path(t_,geom,prj_trans);
672            ras.add_path(path);
673        }
674    }
675}
676
677template <typename T>
678void agg_renderer<T>::process(polygon_pattern_symbolizer const& sym,
679                              Feature const& feature,
680                              proj_transform const& prj_trans)
681{
682    typedef coord_transform2<CoordTransform,geometry2d> path_type;
683    typedef agg::renderer_base<agg::pixfmt_rgba32_plain> ren_base;
684    typedef agg::wrap_mode_repeat wrap_x_type;
685    typedef agg::wrap_mode_repeat wrap_y_type;
686    typedef agg::pixfmt_alpha_blend_rgba<agg::blender_rgba32,
687        agg::row_accessor<agg::int8u>, agg::pixel32_type> rendering_buffer;
688    typedef agg::image_accessor_wrap<rendering_buffer,
689        wrap_x_type,
690        wrap_y_type> img_source_type;
691
692    typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
693
694    typedef agg::renderer_scanline_aa<ren_base,
695        agg::span_allocator<agg::rgba8>,
696        span_gen_type> renderer_type;
697
698
699    agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4);
700    agg::pixfmt_rgba32_plain pixf(buf);
701    ren_base renb(pixf);
702   
703    agg::scanline_u8 sl;
704    ras_ptr->reset();
705    ras_ptr->gamma(agg::gamma_linear());
706
707    std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
708    boost::optional<mapnik::image_ptr> pat = mapnik::image_cache::instance()->find(filename,true);
709
710    if (!pat) return;
711   
712    unsigned w=(*pat)->width();
713    unsigned h=(*pat)->height();
714    agg::row_accessor<agg::int8u> pattern_rbuf((agg::int8u*)(*pat)->getBytes(),w,h,w*4);
715    agg::span_allocator<agg::rgba8> sa;
716    agg::pixfmt_alpha_blend_rgba<agg::blender_rgba32,
717        agg::row_accessor<agg::int8u>, agg::pixel32_type> pixf_pattern(pattern_rbuf);
718    img_source_type img_src(pixf_pattern);
719   
720    double x0=0,y0=0;
721    unsigned num_geometries = feature.num_geometries();
722    if (num_geometries>0)
723    {
724        path_type path(t_,feature.get_geometry(0),prj_trans);
725        path.vertex(&x0,&y0);
726    }
727    unsigned offset_x = unsigned(width_-x0);
728    unsigned offset_y = unsigned(height_-y0);
729    span_gen_type sg(img_src, offset_x, offset_y);
730    renderer_type rp(renb,sa, sg);
731    for (unsigned i=0;i<num_geometries;++i)
732    {
733        geometry2d const& geom = feature.get_geometry(i);
734        if (geom.num_points() > 2)
735        {
736            path_type path(t_,geom,prj_trans);
737            ras_ptr->add_path(path);
738        }
739    }
740    agg::render_scanlines(*ras_ptr, sl, rp);
741}
742
743template <typename T>
744void agg_renderer<T>::process(raster_symbolizer const& sym,
745                              Feature const& feature,
746                              proj_transform const& prj_trans)
747{
748    raster_ptr const& raster=feature.get_raster();
749    if (raster)
750    {
751    // If there's a colorizer defined, use it to color the raster in-place
752    raster_colorizer_ptr colorizer = sym.get_colorizer();
753    if (colorizer)
754        colorizer->colorize(raster);
755       
756        box2d<double> ext=t_.forward(raster->ext_);
757       
758        int start_x = rint(ext.minx());
759        int start_y = rint(ext.miny());
760        int raster_width = rint(ext.width());
761        int raster_height = rint(ext.height());
762        int end_x = start_x + raster_width;
763        int end_y = start_y + raster_height;
764        double err_offs_x = (ext.minx()-start_x + ext.maxx()-end_x)/2;
765        double err_offs_y = (ext.miny()-start_y + ext.maxy()-end_y)/2;
766       
767        if ( raster_width > 0 && raster_height > 0)
768        {
769            image_data_32 target(raster_width,raster_height);
770         
771            if (sym.get_scaling() == "fast") {
772                scale_image<image_data_32>(target,raster->data_);
773            } else if (sym.get_scaling() == "bilinear"){
774                scale_image_bilinear<image_data_32>(target,raster->data_, err_offs_x, err_offs_y);
775            } else if (sym.get_scaling() == "bilinear8"){
776                scale_image_bilinear8<image_data_32>(target,raster->data_, err_offs_x, err_offs_y);
777            } else {
778                scale_image<image_data_32>(target,raster->data_);
779            }
780           
781            if (sym.get_mode() == "normal"){
782                if (sym.get_opacity() == 1.0) {
783                    pixmap_.set_rectangle(start_x,start_y,target);
784                } else {
785                    pixmap_.set_rectangle_alpha2(target,start_x,start_y, sym.get_opacity());
786                }
787            } else if (sym.get_mode() == "grain_merge"){
788                pixmap_.template merge_rectangle<MergeGrain> (target,start_x,start_y, sym.get_opacity());
789            } else if (sym.get_mode() == "grain_merge2"){
790                pixmap_.template merge_rectangle<MergeGrain2> (target,start_x,start_y, sym.get_opacity());
791            } else if (sym.get_mode() == "multiply"){
792                pixmap_.template merge_rectangle<Multiply> (target,start_x,start_y, sym.get_opacity());
793            } else if (sym.get_mode() == "multiply2"){
794                pixmap_.template merge_rectangle<Multiply2> (target,start_x,start_y, sym.get_opacity());
795            } else if (sym.get_mode() == "divide"){
796                pixmap_.template merge_rectangle<Divide> (target,start_x,start_y, sym.get_opacity());
797            } else if (sym.get_mode() == "divide2"){
798                pixmap_.template merge_rectangle<Divide2> (target,start_x,start_y, sym.get_opacity());
799            } else if (sym.get_mode() == "screen"){
800                pixmap_.template merge_rectangle<Screen> (target,start_x,start_y, sym.get_opacity());
801            } else if (sym.get_mode() == "hard_light"){
802                pixmap_.template merge_rectangle<HardLight> (target,start_x,start_y, sym.get_opacity());
803            } else {
804                if (sym.get_opacity() == 1.0){
805                    pixmap_.set_rectangle(start_x,start_y,target);
806                } else {
807                    pixmap_.set_rectangle_alpha2(target,start_x,start_y, sym.get_opacity());
808                }
809            }
810            // TODO: other modes? (add,diff,sub,...)
811        }
812    }
813}
814
815template <typename T>
816void agg_renderer<T>::process(markers_symbolizer const& sym,
817                              Feature const& feature,
818                              proj_transform const& prj_trans)
819{
820    typedef  coord_transform2<CoordTransform,geometry2d> path_type;
821    typedef agg::renderer_base<agg::pixfmt_rgba32_plain> ren_base;
822    typedef agg::renderer_scanline_aa_solid<ren_base> renderer;
823    arrow arrow_;
824    ras_ptr->reset();
825    ras_ptr->gamma(agg::gamma_linear());
826
827
828    agg::scanline_u8 sl;
829    agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4);
830    agg::pixfmt_rgba32_plain pixf(buf);
831    ren_base renb(pixf);
832
833    unsigned r = 0;// fill_.red();
834    unsigned g = 0; //fill_.green();
835    unsigned b = 255; //fill_.blue();
836    unsigned a = 255; //fill_.alpha();
837    renderer ren(renb);
838    for (unsigned i=0;i<feature.num_geometries();++i)
839    {
840        geometry2d const& geom=feature.get_geometry(i);
841        if (geom.num_points() > 1)
842        {
843            path_type path(t_,geom,prj_trans);
844
845            agg::conv_dash <path_type> dash(path);
846            dash.add_dash(20.0,200.0);
847            markers_converter<agg::conv_dash<path_type>,
848                arrow,
849                label_collision_detector4>
850                marker(dash, arrow_, detector_);
851            ras_ptr->add_path(marker);
852        }
853    }
854    ren.color(agg::rgba8(r, g, b, a));
855    agg::render_scanlines(*ras_ptr, sl, ren);
856}
857
858template <typename T>
859void agg_renderer<T>::process(text_symbolizer const& sym,
860                              Feature const& feature,
861                              proj_transform const& prj_trans)
862{
863    typedef  coord_transform2<CoordTransform,geometry2d> path_type;
864
865    expression_ptr name_expr = sym.get_name();
866    if (!name_expr) return;
867    value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature),*name_expr);
868    UnicodeString text = result.to_unicode();
869     
870    if ( sym.get_text_convert() == TOUPPER)
871    {
872        text = text.toUpper();
873    }
874    else if ( sym.get_text_convert() == TOLOWER)
875    {
876        text = text.toLower();
877    }
878
879    if ( text.length() > 0 )
880    {
881        color const& fill = sym.get_fill();
882
883        face_set_ptr faces;
884
885        if (sym.get_fontset().size() > 0)
886        {
887            faces = font_manager_.get_face_set(sym.get_fontset());
888        }
889        else
890        {
891            faces = font_manager_.get_face_set(sym.get_face_name());
892        }
893
894        if (faces->size() > 0)
895        {
896            text_renderer<T> ren(pixmap_, faces);
897            ren.set_pixel_size(sym.get_text_size());
898            ren.set_fill(fill);
899            ren.set_halo_fill(sym.get_halo_fill());
900            ren.set_halo_radius(sym.get_halo_radius());
901            ren.set_opacity(sym.get_opacity());
902
903            placement_finder<label_collision_detector4> finder(detector_);
904
905            string_info info(text);
906
907            faces->get_string_info(info);
908            unsigned num_geom = feature.num_geometries();
909            for (unsigned i=0;i<num_geom;++i)
910            {
911                geometry2d const& geom = feature.get_geometry(i);
912                if (geom.num_points() > 0) // don't bother with empty geometries
913                {
914                    path_type path(t_,geom,prj_trans);
915                    placement text_placement(info,sym);
916                    text_placement.avoid_edges = sym.get_avoid_edges();
917                    if (sym.get_label_placement() == POINT_PLACEMENT)
918                    {
919                        double label_x, label_y, z=0.0;
920                        geom.label_position(&label_x, &label_y);
921                        prj_trans.backward(label_x,label_y, z);
922                        t_.forward(&label_x,&label_y);
923                        finder.find_point_placement(text_placement,label_x,label_y,sym.get_vertical_alignment(),sym.get_line_spacing(),
924                                                    sym.get_character_spacing(),sym.get_horizontal_alignment(),sym.get_justify_alignment());
925                        finder.update_detector(text_placement);
926                    }
927                    else if ( geom.num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT)
928                    {
929                        finder.find_line_placements<path_type>(text_placement,path);
930                    }
931
932                    for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii)
933                    {
934                        double x = text_placement.placements[ii].starting_x;
935                        double y = text_placement.placements[ii].starting_y;
936                        box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
937                        ren.render(x,y);
938                    }
939                }
940            }
941        }
942        else
943        {
944            throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'");
945        }
946    }
947}
948template class agg_renderer<image_32>;
949}
Note: See TracBrowser for help on using the browser.