Subversion Repositories public

Rev

Rev 274 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

//
// C++ Implementation: render
//
// Description: Renders a map from some shape files. This class assumes,
//              that the shape files are in open street map format!
//
//
// Author: Andreas Theofilu <andreas@theosys.at>, (C) 2009
//
// Copyright: See COPYING file that comes with this distribution
//
//

#define BOOST_SPIRIT_THREADSAFE
#include <mapnik/map.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/config_error.hpp>

#include "config.h"
#include "render.h"

#define CON_MAP                 100
#define CON_STYLE               101
#define CON_RULE                102
#define CON_LINESYMBOLIZER      103
#define CON_POINTSYMBOLIZER     104
#define CON_POLYGONSYMBOLIZER   105
#define CON_TEXTSYMBOLIZER      106
#define CON_POLYGONPATTERNSYMBOLIZER    107
#define CON_LAYER               108
#define CON_DATASOURCE          109

#define FLD_FILTER              200
#define FLD_CSSPARAMETER        201
#define FLD_MINSCALE            202
#define FLD_MAXSCALE            203
#define FLD_STYLENAME           204
#define FLD_PARAMETER           205

#define ATT_FILL                300
#define ATT_FILE                301
#define ATT_TYPE                302
#define ATT_WIDTH               303
#define ATT_HEIGHT              304
#define ATT_SIZE                305
#define ATT_NAME                306
#define ATT_FACENAME            307
#define ATT_DY                  308
#define ATT_HALORADIUS          309
#define ATT_WRAPWIDTH           310
#define ATT_MINDISTANCE         311
#define ATT_MAXDISTANCE         312
#define ATT_PLACEMENT           313
#define ATT_ALLOWOVERLAP        314
#define ATT_STATUS              315
#define ATT_SRS                 316

#define FIRST_CON               100
#define LAST_CON                109

#define FIRST_FLD               200
#define LAST_FLD                205

#define FIRST_ATT               300
#define LAST_ATT                316

KEYS keys[] = {
        // Containers
        { CON_MAP                       QString("Map") },
        { CON_STYLE                     QString("Style") },
        { CON_RULE                      QString("Rule") },
        { CON_LINESYMBOLIZER            QString("LineSymbolizer") },
        { CON_POINTSYMBOLIZER           QString("PointSymbolizer") },
        { CON_POLYGONSYMBOLIZER         QString("PolygonSymbolizer") },
        { CON_TEXTSYMBOLIZER            QString("TextSymbolizer") },
        { CON_POLYGONPATTERNSYMBOLIZER  QString("PolygonPatternSymbolizer") },
        { CON_LAYER                     QString("Layer") },
        { CON_DATASOURCE                QString("Datasource") },
        // Fields
        { FLD_FILTER                    QString("Filter") },
        { FLD_CSSPARAMETER              QString("CSSParameter") },
        { FLD_MINSCALE                  QString("MinScaleDenominator") },
        { FLD_MAXSCALE                  QString("MaxScaleDenominator") },
        { FLD_STYLENAME                 QString("StyleName") },
        { FLD_PARAMETER                 QString("Parameter") },
        // Attributes
        { ATT_FILL                      QString("fill") },
        { ATT_NAME                      QString("name") },
        { ATT_FILE                      QString("file") },
        { ATT_TYPE                      QString("type") },
        { ATT_WIDTH                     QString("width") },
        { ATT_HEIGHT                    QString("height") },
        { ATT_SIZE                      QString("size") },
        { ATT_FACENAME                  QString("face_name") },
        { ATT_DY                        QString("dy") },
        { ATT_HALORADIUS                QString("halo_radius") },
        { ATT_WRAPWIDTH                 QString("wrap_width") },
        { ATT_MINDISTANCE               QString("min_distance") },
        { ATT_MAXDISTANCE               QString("max_distance") },
        { ATT_PLACEMAENT                QString("placement") },
        { ATT_ALLOWOVERLAP              QString("allow_overlap") },
        { ATT_STATUS                    QString("status") },
        { ATT_SRS                       QString("srs") },
        { 0                             QString::null }
};

render::render()
{
        Layer = 0;
        Style = 0;
        Rule = 0;
        LineSymbolizer = 0;
        PolygonSymbolizer = 0;
        TextSymbolizer = 0;
        PointSymbolizer = 0;
        PolygonPatternSymbolizer = 0;
        ShieldSymbolizer = 0;
        LinePatternSymbolizer = 0;
}

bool render::startDocument()
{
        indent = 0;

        if (firstStyle)         // free if allocated
        {
           Style = firstStyle;

           while (Style)
           {
              if (Style->rule)
              {
                 RULE *rule = Style->rule;
                 STYLE *sakt = Style->next;

                 while (rule)
                 {
                    RULE *rakt = rule->next;
                    LINESYMBOLIZER *LineSymbolizer = rule->LineSymbolizer;
                    POLYGONSYMBOLIZER *PolygonSymbolizer = rule->PolygonSymbolizer;
                    TEXTSYMBOLIZER *TextSymbolizer = rule->TextSymbolizer;
                    POINTSYMBOLIZER *PointSymbolizer = rule->PointSymbolizer;
                    POLYGONPATTERNSYMBOLIZER *PolygonPatternSymbolizer = rule->PolygonPatternSymbolizer;
                    SHIELDSYMBOLIZER *ShieldSymbolizer = rule->ShielSymbolizer;
                    LINEPATTERNSYMBOLIZER *LinePatternSymbolizer = rule->LinePatternSymbolizer;

                    while (LineSymbolizer)
                    {
                       LINESYMBOLIZER *akt = LineSymbolizer->next;
                       delete LineSymbolizer;
                       LineSymbolizer = akt;
                    }

                    while (PolygonSymbolizer)
                    {
                       POLYGONSYMBOLIZER *akt = PolygonSymbolizer->next;
                       delete PolygonSymbolizer;
                       PolygonSymbolizer = akt;
                    }

                    while (TextSymbolizer)
                    {
                       TEXTSYMBOLIZER *akt = TextSymbolizer->next;
                       delete TextSymbolizer;
                       TextSymbolizer = akt;
                    }

                    while (PointSymbolizer)
                    {
                       POINTSYMBOLIZER *akt = PointSymbolizer->next;
                       delete PointSymbolizer;
                       PointSymbolizer = akt;
                    }

                    while (PolygonPatternSymbolizer)
                    {
                       POLYGONPATTERNSYMBOLIZER *akt = PolygonPatternSymbolizer->next;
                       delete PolygonPatternSymbolizer;
                       PolygonPatternSymbolizer = akt;
                    }

                    while (ShieldSymbolizer)
                    {
                       SHIELDSYMBOLIZER *akt = ShieldSymbolizer->next;
                       delete ShieldSymbolizer;
                       ShieldSymbolizer = akt;
                    }

                    while (LinePatternSymbolizer)
                    {
                       LINEPATTERNSYMBOLIZER *akt = LinePatternSymbolizer->next;
                       delete LinePatternSymbolizer;
                       LinePatternSymbolizer = akt;
                    }

                    delete rule;
                    rule = rakt;
                 }
              }

              delete Style;
              Style = sakt;
           }
        }

        Style = firstStyle = lastStyle = 0;
        return true;
}

/*
 * This is called every time a new start element was parsed.
 */
bool render::startElement( const QString&, const QString&,
                                    const QString& qName,
                                    const QXmlAttributes& att)
{
int i = FIRST_CON;
int index;

        indent++;

        while (i < LAST_CON)
        {
           if (qName.toLower() == getKey(i).toLower())
           {
              switch (i)
              {
                 case CON_MAP:
                    if ((index = att.index(QString("bgcolor"))) != -1)
                       MapPars.bgcolor = color_factory::from_string(att.value(index).toAscii().data());

                    if ((index = att.index(QString("buffer_size"))) != -1)
                       MapPars.buf_size = att.value(index).toInt();

                    if ((index = att.index(QString("srs"))) != -1)
                       MapPars.srs = att.value(index);
                 break;

                 case CON_STYLE:
                    if (!lastStyle)
                    {
                       Style = new STYLE;
                       fistStyle = lastStyle = Style;
                       memset (Style, 0, sizeof (STYLE));
                    }
                    else
                    {
                       Style = new STYLE;
                       memset (Style, 0, sizeof (STYLE));
                       lastStyle->next = Style;
                       lastStyle = Style;
                    }

                    if ((index = att.index(QString("name"))) != -1)
                       Style->name = att.value(index);
                    else
                    {
                       KMessageBox::error(0, i18n("Error parsing %1: Open STYLE wihout a name!").arg(XmlPath));
                       return false;
                    }
                 break;

                 case CON_RULE:
                    if (!Style)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1: Open RULE outside of a STYLE!").arg(XmlPath));
                       return false;
                    }

                    Rule = getLastRule (Style->rule);

                    if (!Rule)
                    {
                       Rule = new RULE;
                       memset (Rule, 0, sizeof(RULE));
                       Style->rule = Rule;
                    }
                    else
                    {
                       Rule->next = new RULE;
                       Rule = Rule->next;
                       memset (Rule, 0, sizeof(RULE));
                    }
                 break;

                 case CON_POINTSYMBOLIZER:
                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1: Open POINTSYMBOLIZER outside of a RULE!").arg(XmlPath));
                       return false;
                    }

                    PointSymbolizer = getLastPointSymbolizer(Rule->PointSymbolizer);

                    if (!PointSymbolizer)
                    {
                       PointSymbolizer = new POINTSYMBOLIZER;
                       memset (PointSymbolizer, 0, sizeof(POINTSYMBOLIZER));
                       Rule->PointSymbolizer = PointSymbolizer;
                    }
                    else
                    {
                       PointSymbolizer->next = new POINTSYMBOLIZER;
                       PointSymbolizer = PointSymbolizer->next;
                       memset (PointSymbolizer, 0, sizeof(POINTSYMBOLIZER));
                    }

                    if ((index = att.index(QString("file"))) != -1)
                       PointSymbolizer->file = att.value(index);

                    if ((index = att.index(QString("type"))) != -1)
                    {
                       QString ty = att.value(index);

                       if (ty.toLower() == QString("png"))
                          PointSymbolizer->type = type_png;
                       else if (ty.toLower() == QString("gif"))
                          PointSymbolizer->type = type_gif;
                       else if (ty.toLower() == QString("jpg"))
                          PointSymbolizer->type = type_jpg;
                       else if (ty.toLower() == QString("xpm"))
                          PointSymbolizer->type = type_xpm;
                       else if (ty.toLower() == QString("bmp"))
                          PointSymbolizer->type = type_xmp;
                       else if (ty.toLower() == QString("tif") || ty.toLower() == QString("tiff"))
                          PointSymbolizer->type = type_tif;
                    }

                    if ((index = add.index(QString("width"))) != -1)
                       PointSymbolizer->width = att.value(index).toDouble();

                    if ((index = add.index(QString("height"))) != -1)
                       PointSymbolizer->height = att.value(index).toDouble();

                    if ((index = add.index(QString("allow_overlap"))) != -1)
                    {
                       if (att.value(index).toLower() == QString("true"))
                          PointSymbolizer->allow_overlap = true;
                       else
                          PointSymbolizer->allow_overlap = false;
                    }
                 break;

                 break;

                 case CON_LINESYMBOLIZER:
                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1: Open LINESYMBOLIZER outside of a RULE!").arg(XmlPath));
                       return false;
                    }

                    LineSymbolizer = getLastLineSymbolizer(Rule->LineSymbolizer);

                    if (!LineSymbolizer)
                    {
                       LineSymbolizer = new LINESYMBOLIZER;
                       memset (LineSymbolizer, 0, sizeof(LINESYMBOLIZER));
                       Rule->LineSymbolizer = LineSymbolizer;
                    }
                    else
                    {
                       LineSymbolizer->next = new LINESYMBOLIZER;
                       LineSymbolizer = LineSymbolizer->next;
                       memset (LineSymbolizer, 0, sizeof(LINESYMBOLIZER));
                    }
                 break;

                 case CON_POLYGONSYMBOLIZER:
                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1: Open POLYGONSYMBOLIZER outside of a RULE!").arg(XmlPath));
                       return false;
                    }

                    PolygonSymbolizer = getLastPolygonSymbolizer(Rule->PolygonSymbolizer);

                    if (!PolygonSymbolizer)
                    {
                       PolygonSymbolizer = new POLYGONSYMBOLIZER;
                       memset (PolygonSymbolizer, 0, sizeof(POLYGONSYMBOLIZER));
                       Rule->PolygonSymbolizer = PolygonSymbolizer;
                    }
                    else
                    {
                       PolygonSymbolizer->next = new POLYGONSYMBOLIZER;
                       PolygonSymbolizer = PolygonSymbolizer->next;
                       memset (PolygonSymbolizer, 0, sizeof(POLYGONSYMBOLIZER));
                    }
                 break;

                 case CON_TEXTSYMBOLIZER:
                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1: Open TEXTSYMBOLIZER outside of a RULE!").arg(XmlPath));
                       return false;
                    }

                    TextSymbolizer = getLastTextSymbolizer(Rule->TextSymbolizer);

                    if (!TextSymbolizer)
                    {
                       TextSymbolizer = new TEXTSYMBOLIZER;
                       memset (TextSymbolizer, 0, sizeof(TEXTSYMBOLIZER));
                       Rule->TextSymbolizer = TextSymbolizer;
                    }
                    else
                    {
                       TextSymbolizer->next = new TEXTSYMBOLIZER;
                       TextSymbolizer = TextSymbolizer->next;
                       memset (TextSymbolizer, 0, sizeof(TEXTSYMBOLIZER));
                    }

                    if ((index = att.index(QString("name"))) != -1)
                       TextSymbolizer->name = att.value(index);

                    if ((index = att.index(QString("face_name"))) != -1)
                       TextSymbolizer->face_name = att.value(index);

                    if ((index = att.index(QString("size"))) != -1)
                       TextSymbolizer->size = att.value(index).toDouble();

                    if ((index = att.index(QString("fill"))) != -1)
                       TextSymbolizer->fill = 
                 break;
        }
}

/*
 * This is called every time an element is closed.
 */
bool render::endElement( const QString&, const QString&, const QString& qName)
{
}

/*
 * The reader calls this function when it has parsed a chunk of character data
 * - either normal character data or character data inside a CDATA section.
 */
bool render::characters (const QString& ch)
{
}

QString render::getKey (int pos)
{
int i = 0;

        while (keys[i].id > 0)
        {
           if (keys[i].id == pos)
              return keys[i].name;

           i++;
        }

        return QString::null;
}

bool render::getMap (double lx, double ly, double rx double ry)
{
int width, height;

        datasource_cache::instance()->register_datasources(MAPNIK_PLUGIN_PATH + "/");
        freetype_engine::register_font(MAPNIK_FONTS + "/DejaVuSans.ttf");

        width = label.width();
        height = label.height();

        Map m(width, height, "+proj=merc +datum=WGS84  +k=1.0 +units=m +over +no_defs");
        m.set_background(color_factory::from_string("white"));

        // create styles
        // world1
        feature_type_style world1_style;
        addRule(&world1_style, 0, 6000000.0, 250000000000.0, Color(0xf2, 0xef, 0xe9), Color(0xb5, 0xd0, 0xd0), 0.5, 0, 0, 0);

        // world
        feature_type_style world_style;
        addRule(&world_style, 0, 600000.0, 6000000.0, Color(0xf2, 0xef, 0xe9), 0, 0.0, 0, 0, 0);

        // coast_poly
        feature_type_style coast_poly_style;
        addRule(&coas_poly_style, 0, -1.0, 600000.0, Color(0xf2, 0xef, 0xe9), 0, 0.0, 0, 0, 0);

        // builtup
        feature_type_style builtup_style;
        addRule(&builtup_style, 0, 500000.0, 2500000.0, Color(0x0d, 0x0d, 0x0d), 0, 0.0, 0, 0, 0);

        // places
        feature_type_style places_style;
        text_symbolizer places_ts = addTextSymbolizer("place_name", "DejaVu Sans Book", 10, Color(0x04, 0x04, 0x04), 1, 0.0);
        places_style.append(places_ts);
        addRule(&places_style, 0, 10000000.0, 50000000.0, 0, 0, 0.0, 0, 0, 0);

        // stations
        feature_type_style stations_style;
        addRulePoint(&stations_style, "[railway]='station'", 25000.0, 250000.0, 0, 0, 0.0, QString("station_small.png"), 5, 5);
        addRulePoint(&stations_style, "[railway]='station'", -1.0, 25000.0, 0, 0, 0.0, QString("station.png", 9, 9);
        addRulePoint(&stations_style, "[railway]='halt' or [railway]='tram_stop'", -1.0, 100000.0, 0, 0, 0.0, QString("halt.png"), 3, 3);

        text_symbolizer stations_ts = addTextSymbolizer("name", "DejaVu Sans Bold", 8, Color(0, 0, 0), 1, 0, -8.0);
        stations_style.append(stations_ts);
        addRulePoint(&stations_style, "[railway]='halt'", 25000.0, 50000.0, 0, 0, 0.0, 0, 0, 0, 0);

        text_symbolizer stations_ts1 = addTextSymbolizer("name", "DejaVu Sans Bold", 10, Color(0, 0, 0), 1, 0, -14.0);
        stations_style.append(stations_ts1);
        addRule(&stations_style, "[railway] ='halt'", -1.0, 25000.0, 0, 0, 0.0, 0, 0, 0);

        text_symbolizer stations_ts2 = addTextSymbolizer("name", "DejaVu Sans Bold", 9, Color(0, 0, 0), 1, 0, -8.0);
        stations_style.append(stations_ts2);
        addRule(&stations_style, "[railway]='station'", 25000.0, 50000.0, 0, 0, 0.0, 0, 0, 0);

        text_symbolizer stations_ts3 = addTextSymbolizer("name", "DejaVu Sans Bold", 12, Color(0, 0, 0), 1, 0, -14.0);
        stations_style.append(stations_ts3);
        addRule(&stations_style, "[railway]='station'", -1.0, 25000.0, 0, 0, 0.0, 0, 0, 0);
        addRulePoint(&stations_style, "[railway]='level_crossing'", 10000.0, 50000.0, 0, 0, 0.0, QString("level_crossing.png"), 7, 7);

        // leisure
        feature_type_style leisure_style;

        addRule(&leisure_style, "[man_made] = 'pier'", -1.0, 100000.0, Color(0xed, 0xed, 0xed), color_factory::from_string("grey"), 0.3, 0, 0, 0);
        addRule(&leisure_style, "[highway] = 'residential'", -1.0, 50000.0, Color(255, 255, 255), Color(0x09, 0x09, 0x09), 1.0, 0, 0, 0);
        addRule(&leisure_style, "[highway] = 'pedestrian'", -1.0, 50000.0, Color(0xed, 0xed, 0xed), color_factory::from_string("grey"), 0.5, 0, 0, 0);
        addRule(&leisure_style, "[leisure] = 'playground'", -1.0, 100000.0, Color(0xcc, 0xff, 0xff), Color(0x06, 0x06, 0x06), 0.3, 0, 0, 0);
        addRule(&leisure_style, "[tourism] = 'attraction'", -1.0, 100000.0, Color(0xf2, 0xca, 0xea), 0, -1.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'quarry'", -1.0, 500000.0, 0, color_factory::from_string("grey"), 0.5, QString("quarry2.png"), 30, 30);
        addRule(&leisure_style, "[leisure] = 'nature_reserve' or [landuse] = 'vineyard'", 100000.0, 1000000.0, Color(0xab, 0xdf, 0x96), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'vineyard'", 20000.0, 100000.0, 0, 0, 0.0, QString("vineyard.png"), 19, 21);
        addRule(&leisure_style, "[landuse] = 'vineyard'", -1.0, 100000.0, 0, 0, 0.0, QString("vineyard.png"), 29, 29);
        addRule(&leisure_style, "[leisure] = 'nature_reserve'", 50000.0, 100000.0, 0, 0, 0.0, QString("nature_reserve.png"), 21, 24);
        addRule(&leisure_style, "[leisure] = 'nature_reserve'", -1.0, 50000.0, 0, 0, 0.0, QString("nature_reserve2.png"), 42, 48);
        addRule(&leisure_style, "[landuse] = 'cemetery'", 20000.0, 1000000.0, Color(0xaa, 0xcb, 0xaf), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'residential'", 1000.0, 1000000.0, Color(0x0d, 0x0d, 0x0d), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[military] = 'barracks'", 1000.0, 1000000.0, Color(0xff, 0x8f, 0x8f), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[military] = 'danger_area'", 500000.0, 2000000.0, color_factory::from_string("pink"), 0, 0.0, 0, 0, 0); // FIXME: fill-opacity 0.3 is missing!
        addRule(&leisure_style, "[military] = 'danger_area'", 1000.0, 500000.0, 0, 0, 0.0, QString("danger.png"), 30, 30);
        addRule(&leisure_style, "[landuse] = 'cemetery'", -1.0, 50000.0, 0, 0, 0.0, QString("grave_yard.png"), 16, 16);
        addRule(&leisure_style, "[landuse] = 'meadow'", -1.0, 1000000.0, Color(0xcf, 0xec, 0xa8), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[leisure] = 'park'", -1.0, 1000000.0, Color(0xb6, 0xfd, 0xb6), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[tourism] = 'zoo'", -1.0, 1000000.0, 0, 0, 0.0, QString("zoo.png"), 21, 24);
        addRule(&leisure_style, "[leisure] = 'common'", -1.0, 1000000.0, Color(0xcf, 0xec, 0xa8), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[leisure] = 'garden'", -1.0, 1000000.0, Color(0xcf, 0xec, 0xa8), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[leisure] = 'golf_course'", -1.0, 1000000.0, Color(0xb5, 0xe3, 0xb5), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'allotments'", -1.0, 1000000.0, Color(0xc8, 0xb0, 0x84), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'forest'", 50000.0, 2000000.0, Color(0x8d, 0xc5, 0x6c), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'forest'", -1.0, 50000.0, 0, 0, 0.0, QString("forest.png"), 21, 24);
        addRule(&leisure_style, "[landuse] = 'farm'", -1.0, 2000000.0, Color(0xea, 0xd8, 0xbd), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'recreation_ground'", -1.0, 1000000.0, Color(0xcf, 0xec, 0xa8), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'village_green'", -1.0, 500000.0, Color(0xcf, 0xec, 0xa8), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'retail'", -1.0, 1000000.0, Color(0xf1, 0xda, 0xda), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'retail'", -1.0, 25000.0, 0, color_factory::from_string("red"), 0.3, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'industrial'", -1.0, 1000000.0, Color(0xff, 0xae, 0xb9), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[power] = 'station'", 200000.0, 1000000.0, Color(0x0b, 0x0b, 0x0b), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[power] = 'station'", -1.0, 200000.0, Color(0x0b, 0x0b, 0x0b), Color(0x05, 0x05, 0x05), 0.4, 0, 0, 0);
        addRule(&leisure_style, "[power] = 'sub_station'", -1.0, 100000.0, Color(0x0b, 0x0b, 0x0b), Color(0x05, 0x05, 0x05), 0.4, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'commercial'", -1.0, 1000000.0, Color(0xef, 0xc8, 0xc8), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'brownfield' or [landuse]='landfill'", -1, 1000000.0, Color(0x9d, 0x9d, 0x6c), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[natural] = 'wood' or [landuse] = 'wood'", -1.0, 1000000.0, Color(0xae, 0xd1, 0xa0), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[natural] = 'heath'", -1.0, 1000000.0, Color(0xff, 0xff, 0xc0), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[landuse] = 'basin'", -1.0, 5000000.0, Color(0xb5, 0xd0, 0xd0), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[amenity] = 'university' or [amenity] = 'college' or [amenity] = 'school' or [amenity]='hospital'", -1.0, 1000000.0, Color(0xf0, 0xf0, 0xd8), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[amenity] = 'university' or [amenity] = 'college' or [amenity] = 'school' or [amenity]='hospital'", -1.0, 250000.0, 0, color_factory::from_string("brown"), 0.3, 0, 0, 0);
        addRule(&leisure_style, "[amenity] = 'parking'", -1.0, 1000000.0, Color(0xf7, 0xef, 0xb7),  0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[amenity] = 'parking'", -1.0, 25000.0, 0, Color(0xee, 0xee, 0xd1), 0.3, 0, 0, 0);
        addRule(&leisure_style, "[railway] = 'station' or [building] = 'station'", -1.0, 1000000.0, Color(0xff, 0xf6, 0x8f), 0, 0.0, 0, 0, 0); // FIXME: fill-opacity = 0.5 is missing!
        addRule(&leisure_style, "[building] = 'supermarket'", -1.0, 1000000.0, color_factory::from_string("pink"), 0, 0.0, 0, 0, 0); // FIXME: fill-opacity = 0.5 is missing!
        addRule(&leisure_style, "[building] <> 'station' and [building] <> 'supermarket' and [building] <> ''", -1.0, 1000000.0, Color(0xcc, 0x99, 0x99), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[amenity] = 'place_of_worship'", 20000.0, 1000000.0, Color(0x07, 0x07, 0x07), 0, 0.0, 0, 0, 0); // FIXME: fill-opacity = 0.5 is missing!
        addRule(&leisure_style, "[amenity] = 'place_of_worship'", -1.0, 20000.0, Color(0x07, 0x07, 0x07), Color(0x01, 0x01, 0x01), 0.3, 0, 0, 0);
        addRule(&leisure_style, "[leisure] = 'sports_centre' or [leisure]='stadium' or [leisure]='track'", -1.0, 1000000.0, Color(0x33, 0xcc, 0x99), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[leisure] = 'pitch'", -1.0, 1000000.0, Color(0x8a, 0xd3, 0xaf), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[aeroway] = 'terminal'", -1.0, 200000.0, Color(0xcc, 0x99, 0xff), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[aeroway] = 'terminal'", -1.0, 50000.0, 0, Color(0x33, 0x00, 0x66), 0.2, 0, 0, 0);
        addRule(&leisure_style, "[aeroway] = 'apron'", -1.0, 200000.0, Color(0xf0, 0xe0, 0xff), 0, 0.0, 0, 0, 0);
        addRule(&leisure_style, "[natural] = 'beach'", -1.0, 100000.0, 0, 0, 0.0, QString("beach.png"), 10, 10);
}

void render::addRule (feature_type_style &fts, char *filter, double minscale, double maxscale, Color &polcol, Color &symcol, double symwidth, QString &pattern, int pw, int ph)
{
        rule_type rule;

        if (minscale >= 0.0)
           rule.set_min_scale(minscale);

        if (maxscale >= 0.0)
           rule.set_max_scale(maxscale);

        if (pattern && pw > 0 && ph > 0)
        {
        QString ptf = KStandardDirs::findRessource("icon", pattern);

           rule.append(polygon_pattern_symbolizer(ptf.toAscii().data(), "png", pw, ph));
        }

        if (filter)
           rule.set_filter(create_filter(filter));

        if (polcol)
           rule.append(polygon_symbolizer(polcol));

        if (symcol)
        {
           stroke stk (symcol);

           if (symwidth >= 0.0)
              stk.set_width(0.3);

           rule.append(line_symbolizer(stk));
        }

        fts.add_rule(rule);
}

void render::addRulePoint (feature_type_style &fts, char *filter, double minscale, double maxscale, Color &polcol, Color &symcol, double symwidth, QString &pattern, int pw, int ph)
{
        rule_type rule;

        if (minscale >= 0.0)
           rule.set_min_scale(minscale);

        if (maxscale >= 0.0)
           rule.set_max_scale(maxscale);

        if (pattern && pw > 0 && ph > 0)
        {
        QString ptf = KStandardDirs::findRessource("icon", pattern);

           rule.append(point_symbolizer(ptf.toAscii().data(), "png", pw, ph));
        }

        if (filter)
           rule.set_filter(create_filter(filter));

        if (polcol)
           rule.append(polygon_symbolizer(polcol));

        if (symcol)
        {
           stroke stk (symcol);

           if (symwidth >= 0.0)
              stk.set_width(0.3);

           rule.append(line_symbolizer(stk));
        }

        fts.add_rule(rule);
}

text_symbolizer &render::addTextSymbolizer (char *name, char *font, int size, Color &col, int radius, int wrap, double dy)
{
text_symbolizer ts(name, font, size, Color(0, 0, 0));

        if (vol && radius > 0)
        {
           ts.set_halo_fill(halo);
           ts.set_halo_radius(radius);
        }

        if (dy < 0.0)
           ts.set_max_char_angle_delta(dy);

        if (wrap >= 0)
           ts.set_wrap_width(wrap);

        return &ts;
}

RULE *render::getLastRule(RULE *first)
{
RULE *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

POINTSYMBOLIZER *render::getLastPointSymbolizer(POINTSYMBOLIZER *first)
{
POINTSYMBOLIZER *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}