root/trunk/src/agg_renderer.cpp @ 1657

Revision 1657, 29.7 kB (checked in by dane, 6 months ago)

restore default behavior of PointSymbolizer when used without an image, by defaulting to 4x4 black pixel - TODO - expose colors, shapes, and size for this in the future

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