source: trunk/renderer.c @ 15

Last change on this file since 15 was 15, checked in by marius, 6 years ago

adding support for naming ways

  • Property svn:eol-style set to native
  • Property svn:keywords set to "Date Author Id Revision HeadURL"
  • Property svn:mime-type set to text/plain
File size: 12.4 KB
Line 
1/*
2 * Memphis - Cairo Rederer for OSM in C
3 * Copyright (C) 2008  <marius.rieder@durchmesser.ch>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19
20#include <math.h>
21#include <time.h>
22#include <cairo.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "main.h"
28#include "osm05.h"
29#include "libmercator.h"
30#include "list.h"
31#include "renderer.h"
32#include "ruleset.h"
33#include "strlist.h"
34#include "textpath.h"
35
36// External Vars
37extern memphisOpt   *opts;
38extern strList      *keyStrings;
39extern strList      *valStrings;
40
41/*
42 * function: drawPath
43 * @cr  Array of cairo resources
44 * @nd  Liked list if osmNd's
45 *
46 * This function is used to prepare a Path.
47 */
48void drawPath(renderInfo *info, osmNd *nd) {
49    if (opts->debug > 1)
50        fprintf(stdout,"drawPath\n");
51    coordinates xy;
52    int z;
53
54    for (z=0;z<=opts->maxlayer-opts->minlayer;z++) {
55        xy = coord2xy(nd->node->lat, nd->node->lon, z+opts->minlayer);
56        cairo_move_to(info->cr[z], xy.x-info->offset[z].x,
57                                    xy.y-info->offset[z].y);
58    }
59    nd = nd->next;
60    while(nd) {
61        for (z=0;z<=opts->maxlayer-opts->minlayer;z++) {
62            xy = coord2xy(nd->node->lat, nd->node->lon, z+opts->minlayer);
63            cairo_line_to(info->cr[z],
64                            xy.x-info->offset[z].x,
65                            xy.y-info->offset[z].y);
66        }
67        nd = nd->next;
68    }
69}
70
71/*
72 * function: strokePath
73 * @cr  Array of cairo resources
74 *
75 * This function is stroke all current path without drawing anithing.
76 */
77void strokePath(renderInfo *info) {
78    if (opts->debug > 1)
79        fprintf(stdout,"strokePath\n");
80    int z;
81
82    for (z=0;z<=opts->maxlayer-opts->minlayer;z++) {
83       cairo_set_line_width (info->cr[z], 0);
84       cairo_stroke(info->cr[z]);
85    }
86}
87
88/*
89 * function: drawPolygone
90 *
91 * This function fill the prepared paths with the configured color.
92 */
93void drawPolygone(renderInfo *info, cfgDraw *draw) {
94    if (opts->debug > 1)
95        fprintf(stdout,"drawPolygone\n");
96
97    cairo_surface_t *image;
98    cairo_pattern_t *pattern;
99
100    if(draw->pattern) {
101        char * filename = malloc(50*sizeof(char));
102        int w, h;
103
104        sprintf(filename,"pattern/%s.png",draw->pattern);
105        image = cairo_image_surface_create_from_png(filename);
106        free(filename);
107
108        w = cairo_image_surface_get_width (image);
109        h = cairo_image_surface_get_height (image);
110
111
112
113        pattern = cairo_pattern_create_for_surface (image);
114        cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
115    }
116
117    int z;
118    for (z=0;z<=opts->maxlayer-opts->minlayer;z++) {
119        if (opts->minlayer+z<draw->minlayer || opts->minlayer+z>draw->maxlayer)
120            continue;
121        cairo_set_fill_rule (info->cr[z], CAIRO_FILL_RULE_EVEN_ODD);
122        if(draw->pattern)
123            cairo_set_source (info->cr[z], pattern);
124        else
125            cairo_set_source_rgb (info->cr[z],
126                                    (double)draw->color[0]/(double)255,
127                                    (double)draw->color[1]/(double)255,
128                                    (double)draw->color[2]/(double)255);
129
130        cairo_fill_preserve(info->cr[z]);
131    }
132
133    if(draw->pattern) {
134        cairo_pattern_destroy (pattern);
135        cairo_surface_destroy (image);
136    }
137}
138
139/*
140 * function: drawLine
141 *
142 * This function draw the prepared paths with the configured color.
143 */
144void drawLine(renderInfo *info, cfgDraw *draw) {
145    if (opts->debug > 1)
146        fprintf(stdout,"drawLine\n");
147
148    int z;
149    for (z=0;z<=opts->maxlayer-opts->minlayer;z++) {
150        if (opts->minlayer+z<draw->minlayer || opts->minlayer+z>draw->maxlayer)
151            continue;
152
153        cairo_set_line_cap  (info->cr[z], CAIRO_LINE_CAP_ROUND);
154        cairo_set_line_width (info->cr[z], draw->width*LINESIZE(z));
155
156        cairo_set_source_rgb (info->cr[z],
157                                    (double)draw->color[0]/(double)255,
158                                    (double)draw->color[1]/(double)255,
159                                    (double)draw->color[2]/(double)255);
160        cairo_stroke_preserve(info->cr[z]);
161    }
162}
163
164/*
165 * function: drawText
166 */
167void drawText(renderInfo *info, char *text, cfgDraw *draw) {
168    if (opts->debug > 1)
169        fprintf(stdout,"drawText\n");
170
171    int z;
172    for (z=0;z<=opts->maxlayer-opts->minlayer;z++) {
173        if (opts->minlayer+z<draw->minlayer || opts->minlayer+z>draw->maxlayer)
174            continue;
175           
176        cairo_select_font_face (info->cr[z], "Sans", CAIRO_FONT_SLANT_NORMAL,
177                                        CAIRO_FONT_WEIGHT_NORMAL);
178        cairo_set_source_rgb (info->cr[z], (double)draw->color[0]/(double)255,
179                              (double)draw->color[1]/(double)255,
180                              (double)draw->color[2]/(double)255);
181        cairo_set_font_size (info->cr[z], draw->width*LINESIZE(z));
182        textPath(info->cr[z], text);
183    }
184}
185
186/**
187 *
188 */
189int stringInStrings(char *string, char **strings) {
190    if (opts->debug > 1)
191        fprintf(stdout,"stringInStrings\n");
192    int r=0;
193    while (*strings != NULL) {
194        if (string == *strings) {
195            return(1);
196        }
197        if(strcmp(*strings,"*") == 0)
198            r = 2;
199        if(strcmp(*strings,"~") == 0)
200            r = 3;
201
202        strings++;
203    }
204    return(r);
205}
206
207int matchRule(cfgRule *rule, osmTag *tag) {
208    if (opts->debug > 1)
209        fprintf(stdout,"matchRule\n");
210    int k, v;
211    while(tag) {
212        k = 0;
213        k = stringInStrings(tag->key, rule->key);
214        v = 0;
215        v = stringInStrings(tag->value, rule->value);
216
217        if (k==1 && v==1)
218            return(1);
219        if (k==1 && v==2)
220            return(1);
221        if (k==0 && v==3)
222            return(1);
223
224        tag = tag->next;
225    }
226    return(0);
227}
228
229int checkRule(cfgRule *rule, osmTag *tag, short int type) {
230    if (opts->debug > 1)
231        fprintf(stdout,"checkRule\n");
232
233    int not;
234    cfgRule *iter;
235
236    if(rule->nparent) {
237        iter = rule->nparent;
238        not = 1;
239    } else {
240        iter = rule->parent;
241        not = 0;
242    }
243
244    while(iter) {
245
246        if(matchRule(iter, tag) == not) {
247            return(0);
248        }
249
250        if(iter->nparent) {
251            iter = iter->nparent;
252            not = 1;
253        } else {
254            iter = iter->parent;
255            not = 0;
256        }
257    }
258
259    if(matchRule(rule, tag)) {
260        return(1);
261    } else {
262        return(-1);
263    }
264
265}
266
267int renderCairo(cfgRules *ruleset, osmFile *osm) {
268    if (opts->debug > 1)
269        fprintf(stdout,"renderCairo\n");
270    int z, l;
271    renderInfo *info;
272
273    info = malloc(sizeof(renderInfo));
274
275    // Initialize all layers
276    for (z=0;z<=opts->maxlayer-opts->minlayer;z++) {
277        coordinates min, max;
278        min = coord2xy(osm->minlat, osm->minlon, z+opts->minlayer);
279        max = coord2xy(osm->maxlat, osm->maxlon, z+opts->minlayer);
280        int w = (int)ceil(max.x-min.x);
281        int h = (int)ceil(min.y-max.y);
282
283        info->offset[z] = coord2xy(osm->maxlat, osm->minlon, z+opts->minlayer);
284
285        info->surface[z] = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,w,h);
286        info->cr[z] = cairo_create(info->surface[z]);
287
288        cairo_rectangle(info->cr[z], 0, 0, w, h);
289        cairo_set_source_rgb(info->cr[z],
290                                    (double)ruleset->background[0]/(double)255,
291                                    (double)ruleset->background[1]/(double)255,
292                                    (double)ruleset->background[2]/(double)255);
293        cairo_fill(info->cr[z]);
294    }
295
296    // Vars uder while looping throug data
297    osmWay      *way;
298    cfgRule     *rule;
299    cfgDraw     *draw;
300    int         paths;
301
302    long start = (long)clock();
303
304    // Start checking osm from bottom layer.
305    for(l=-5;l<=5;l++) {
306
307        if (opts->debug > 0) {
308            fprintf(stdout,"\r Cairo drawing Layer % 2i", l);
309            fflush(stdout);
310        }
311
312        // Process Rule by Rule
313        LIST_FOREACH(rule, ruleset->rule) {
314
315            if(rule->draw != NULL) { // Draw Match first
316
317                paths = 0;
318                // Loop through ways for
319                LIST_FOREACH(way, osm->ways) {
320                    //Only objects on current layer
321                    if(way->layer != l)
322                        continue;
323
324                    if( checkRule(rule, way->tag, WAY) == 1) {
325                        drawPath(info, way->nd);
326                        paths++;
327                    }
328                }
329                if(paths) {
330                    draw = rule->draw;
331                    while(draw) {
332                        switch(draw->type) {
333                            case POLYGONE:
334                                drawPolygone(info,draw);
335                                break;
336                            case LINE:
337                                drawLine(info,draw);
338                                break;
339                        }
340                        draw = draw->next;
341                    }
342                }
343                strokePath(info);
344               
345                paths = 0;
346                // Text Rendering
347                draw = rule->draw;
348                while(draw) {
349                    switch(draw->type) {
350                        case TEXT:
351                            paths++;
352                            break;
353                    }
354                    if(paths)
355                        break;
356                    draw = draw->next;
357                }
358                if(paths) {
359                    LIST_FOREACH(way, osm->ways) {
360                        //Only objects on current layer
361                        if(way->layer != l || way->name == NULL)
362                            continue;
363
364                        if( checkRule(rule, way->tag, WAY) == 1) {
365                            drawPath(info, way->nd);
366                            drawText(info, way->name, draw);
367                        }
368                    }
369
370                }
371                strokePath(info);
372            }
373            if (rule->ndraw != NULL) { // Draw Else after
374
375                paths = 0;
376                // Loop through ways for
377                LIST_FOREACH(way, osm->ways) {
378                    //Only objects on current layer
379                    if(way->layer != l)
380                        continue;
381
382                    if( checkRule(rule, way->tag, WAY) == -1) {
383                        drawPath(info, way->nd);
384                        paths++;
385                    }
386                }
387                if(paths) {
388                    draw = rule->ndraw;
389                    while(draw) {
390                        switch(draw->type) {
391                            case POLYGONE:
392                                drawPolygone(info,draw);
393                                break;
394                            case LINE:
395                                drawLine(info,draw);
396                                break;
397                        }
398                        draw = draw->next;
399                    }
400                }
401                strokePath(info);
402            }
403        }
404    }
405
406    if (opts->debug > 0)
407        fprintf(stdout,"\r Cairo drawing done. [%fs]\n",
408                    ((long)clock()-start)/(double)CLOCKS_PER_SEC);
409
410    // Saving Images
411    char *filename;
412    filename = malloc(sizeof(char)*50);
413
414    for (z=0;z<=opts->maxlayer-opts->minlayer;z++) {
415        if (opts->debug > 0) {
416            fprintf(stdout,"  Cairo rendering Z%i", z+LAYERMIN);
417            fflush(stdout);
418        }
419        start = (long)clock();
420        sprintf(filename,"tiles/%02i.png",z+LAYERMIN);
421        cairo_surface_write_to_png(info->surface[z], filename);
422        cairo_destroy(info->cr[z]);
423        cairo_surface_destroy(info->surface[z]);
424        if (opts->debug > 0)
425            fprintf(stdout," done.  [%fs]\n",
426                    ((long)clock()-start)/(double)CLOCKS_PER_SEC);
427   }
428
429    return(0);
430}
431
432/*
433 * vim: expandtab shiftwidth=4 tabstop=4:
434 */
435
Note: See TracBrowser for help on using the repository browser.