source: trunk/src/memphis-renderer.c @ 151

Last change on this file since 151 was 151, checked in by simon, 5 years ago

Make cfgRules private

File size: 24.0 KB
Line 
1/*
2 * Memphis - Cairo Rederer for OSM in C
3 * Copyright (C) 2008  Marius Rieder <marius.rieder@durchmesser.ch>
4 * Copyright (C) 2009  Simon Wenner <simon@wenner.ch>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20
21#include <math.h>
22#include <string.h>
23#include <glib/gstdio.h>
24
25#include "memphis-renderer.h"
26#include "memphis-private.h"
27#include "list.h"
28#include "libmercator.h"
29#include "ruleset.h"
30#include "textpath.h"
31
32G_DEFINE_TYPE (MemphisRenderer, memphis_renderer, G_TYPE_OBJECT)
33
34#define MEMPHIS_RENDERER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MEMPHIS_TYPE_RENDERER, MemphisRendererPrivate))
35
36#define MEMPHIS_RENDERER_MIN_ZOOM_LEVEL 12
37#define MEMPHIS_RENDERER_MAX_ZOOM_LEVEL 18
38
39enum
40{
41  PROP_0,
42  PROP_MAP,
43  PROP_RULE_SET,
44  PROP_RESOLUTION,
45  PROP_DEBUG_LEVEL
46};
47
48typedef struct _MemphisRendererPrivate MemphisRendererPrivate;
49struct _MemphisRendererPrivate
50{
51  MemphisMap *map;
52  MemphisRuleSet *rules;
53  guint resolution;
54  gint8 debug_level;
55};
56
57/*
58 * Internal used to save data of a renderer run
59 */
60typedef struct renderInfo_ renderInfo;
61struct renderInfo_ {
62  coordinates     offset;
63  guint           zoom_level;
64  cairo_t         *cr;
65  MemphisRendererPrivate *priv;
66};
67
68/*
69 * Internal used return values for stringInStrings.
70 */
71typedef enum compare_result_e {
72  TAG_CMP_NOT_EQUAL   = 0,
73  TAG_CMP_EQUAL       = 1,
74  TAG_CMP_ANY         = 2,
75  TAG_CMP_MISSING     = 3,
76} compare_result_e;
77
78static int renderCairo (renderInfo *info);
79
80MemphisRenderer*
81memphis_renderer_new ()
82{
83  return g_object_new (MEMPHIS_TYPE_RENDERER, NULL);
84}
85
86MemphisRenderer*
87memphis_renderer_new_full (MemphisRuleSet *rules, MemphisMap *map)
88{
89  MemphisRenderer* r = g_object_new (MEMPHIS_TYPE_RENDERER, NULL);
90  if (map)
91    memphis_renderer_set_map (r, map);
92  if (rules)
93    memphis_renderer_set_rules_set (r, rules);
94  return r;
95}
96
97void
98memphis_renderer_free (MemphisRenderer *renderer)
99{
100  g_return_if_fail (MEMPHIS_IS_RENDERER (renderer));
101 
102  g_object_unref (G_OBJECT (renderer));
103}
104
105/* does not obey resolution settings!
106 * creates a png of the whole data of unpredictable size.
107 * probably not a very useful function for a generic library.
108 * Should be removed! */
109void
110memphis_renderer_draw_png (MemphisRenderer *renderer,
111    gchar *filename, guint zoom_level)
112{
113  g_return_if_fail (MEMPHIS_IS_RENDERER (renderer));
114
115  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (renderer);
116  renderInfo *info;
117  osmFile *osm;
118  cfgRules *ruleset;
119  coordinates min, max;
120  cairo_surface_t *surface;
121
122  g_return_if_fail (MEMPHIS_IS_RULE_SET (priv->rules)
123      && MEMPHIS_IS_MAP (priv->map));
124
125  osm = memphis_map_get_osmFile (priv->map);
126  ruleset = memphis_rule_set_get_cfgRules (priv->rules);
127
128  if (ruleset == NULL || osm == NULL) {
129    if (priv->debug_level > 0)
130      g_fprintf (stdout, " No map and/or rules data: Draw nothing\n");
131    return;
132  }
133
134  if (priv->debug_level > 1)
135    g_fprintf (stdout, "renderCairo\n");
136
137  zoom_level = CLAMP (zoom_level, MEMPHIS_RENDERER_MIN_ZOOM_LEVEL,
138      MEMPHIS_RENDERER_MAX_ZOOM_LEVEL);
139
140  min = coord2xy (osm->minlat, osm->minlon, zoom_level, priv->resolution);
141  max = coord2xy (osm->maxlat, osm->maxlon, zoom_level, priv->resolution);
142  int w = (int) ceil (max.x - min.x);
143  int h = (int) ceil (min.y - max.y);
144
145  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
146
147  info = g_new (renderInfo, 1);
148  info->offset = coord2xy (osm->maxlat, osm->minlon, zoom_level, priv->resolution);
149  info->zoom_level = zoom_level;
150  info->cr = cairo_create (surface);
151  info->priv = priv;
152
153  cairo_rectangle (info->cr, 0, 0, w, h);
154  cairo_set_source_rgb (info->cr,
155      (double)ruleset->background[0] / 255.0,
156      (double)ruleset->background[1] / 255.0,
157      (double)ruleset->background[2] / 255.0);
158  cairo_fill (info->cr);
159
160  renderCairo (info);
161
162  if (priv->debug_level > 0) {
163    g_fprintf (stdout, " Cairo rendering Z%i to '%s'", info->zoom_level, filename);
164    fflush (stdout);
165  }
166  cairo_surface_write_to_png (surface, filename);
167  cairo_destroy (info->cr);
168  cairo_surface_destroy (surface);
169
170  g_free (info);
171
172  if (priv->debug_level > 0)
173    g_fprintf (stdout, " done.\n");
174}
175
176void
177memphis_renderer_draw_tile (MemphisRenderer *renderer,
178    cairo_t *cr,
179    guint x,
180    guint y,
181    guint zoom_level)
182{
183  g_return_if_fail (MEMPHIS_IS_RENDERER (renderer));
184
185  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (renderer);
186  renderInfo *info;
187  osmFile *osm;
188  cfgRules *ruleset;
189  coordinates crd;
190
191  if (!MEMPHIS_IS_RULE_SET (priv->rules) || !MEMPHIS_IS_MAP (priv->map)) {
192    if (priv->debug_level > 0)
193      g_fprintf (stdout, " No map and/or rules data: Draw nothing\n");
194    return;
195  }
196
197  osm = memphis_map_get_osmFile (priv->map);
198  ruleset = memphis_rule_set_get_cfgRules (priv->rules);
199
200  if (ruleset == NULL || osm == NULL) {
201    if (priv->debug_level > 0)
202      g_fprintf (stdout, " No map and/or rules data: Draw nothing\n");
203    return;
204  }
205
206  info = g_new (renderInfo, 1);
207  info->cr = cr;
208  info->zoom_level = CLAMP (zoom_level, MEMPHIS_RENDERER_MIN_ZOOM_LEVEL,
209      MEMPHIS_RENDERER_MAX_ZOOM_LEVEL);
210  info->priv = priv;
211
212  crd = tile2latlon (x, y, info->zoom_level);
213  info->offset = coord2xy (crd.x, crd.y, info->zoom_level, priv->resolution);
214
215  if (priv->debug_level > 0)
216    g_fprintf (stdout, " Cairo rendering tile: (%i, %i, %i)\n", x, y, info->zoom_level);
217
218  cairo_rectangle (info->cr, 0, 0, priv->resolution, priv->resolution);
219  cairo_set_source_rgb (info->cr,
220      (double) ruleset->background[0] / 255.0,
221      (double) ruleset->background[1] / 255.0,
222      (double) ruleset->background[2] / 255.0);
223  cairo_fill (info->cr);
224
225  // TODO: Is this a good cut-off to draw background tiles only?
226  if (x < memphis_renderer_get_max_x_tile (renderer, info->zoom_level) + 2 &&
227      x > memphis_renderer_get_min_x_tile (renderer, info->zoom_level) - 2 &&
228      y < memphis_renderer_get_max_y_tile (renderer, info->zoom_level) + 2 &&
229      y > memphis_renderer_get_min_y_tile (renderer, info->zoom_level) - 2)
230  {
231    renderCairo (info);
232  }
233
234  g_free (info);
235
236  if (priv->debug_level > 0)
237    g_fprintf (stdout, " done.\n");
238}
239
240void
241memphis_renderer_set_resolution (MemphisRenderer *self, guint resolution)
242{
243  g_return_if_fail (MEMPHIS_IS_RENDERER (self));
244
245  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
246  priv->resolution = resolution;
247}
248
249guint
250memphis_renderer_get_resolution (MemphisRenderer *self)
251{
252  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), 0);
253
254  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
255  return priv->resolution;
256}
257
258void
259memphis_renderer_set_map (MemphisRenderer *self, MemphisMap *map)
260{
261  g_return_if_fail (MEMPHIS_IS_RENDERER (self) && MEMPHIS_IS_MAP (map));
262
263  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
264  if (priv->map)
265    g_object_unref (priv->map);
266
267  priv->map = g_object_ref (map);
268}
269
270MemphisMap*
271memphis_renderer_get_map (MemphisRenderer *self)
272{
273  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), NULL);
274
275  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
276  return priv->map;
277}
278
279void
280memphis_renderer_set_rules_set (MemphisRenderer *self,
281    MemphisRuleSet *rules)
282{
283  g_return_if_fail (MEMPHIS_IS_RENDERER (self) &&
284      MEMPHIS_IS_RULE_SET (rules));
285
286  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
287  if (priv->rules)
288    g_object_unref (priv->rules);
289
290  priv->rules = g_object_ref (rules);
291}
292
293MemphisRuleSet*
294memphis_renderer_get_rule_set (MemphisRenderer *self)
295{
296  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), 0);
297
298  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
299  return priv->rules;
300}
301
302void
303memphis_renderer_set_debug_level (MemphisRenderer *self, gint8 debug_level)
304{
305  g_return_if_fail (MEMPHIS_IS_RENDERER (self));
306
307  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
308  priv->debug_level = debug_level;
309  if (priv->map)
310    memphis_map_set_debug_level (priv->map, debug_level);
311  if (priv->rules)
312    memphis_rule_set_set_debug_level (priv->rules, debug_level);
313}
314
315gint8
316memphis_renderer_get_debug_level (MemphisRenderer *self)
317{
318  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), 0);
319
320  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
321  return priv->debug_level;
322}
323
324static void
325memphis_renderer_dispose (GObject *object)
326{
327  MemphisRenderer *self = MEMPHIS_RENDERER (object);
328  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
329
330  if (priv->map)
331    g_object_unref (G_OBJECT (priv->map));
332  if (priv->rules)
333    g_object_unref (G_OBJECT (priv->rules));
334
335  G_OBJECT_CLASS (memphis_renderer_parent_class)->dispose (object);
336}
337
338static void
339memphis_renderer_finalize (GObject *object)
340{
341  G_OBJECT_CLASS (memphis_renderer_parent_class)->finalize (object);
342}
343
344static void
345memphis_renderer_get_property (GObject *object,
346    guint property_id,
347    GValue *value,
348    GParamSpec *pspec)
349{
350  MemphisRenderer *self = MEMPHIS_RENDERER (object);
351  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
352  switch (property_id)
353    {
354      case PROP_RESOLUTION:
355        g_value_set_uint (value, priv->resolution);
356        break;
357      case PROP_MAP:
358        g_value_set_object (value, priv->map);
359        break;
360      case PROP_RULE_SET:
361        g_value_set_object (value, priv->rules);
362        break;
363      case PROP_DEBUG_LEVEL:
364        g_value_set_int (value, priv->debug_level);
365        break;
366      default:
367        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
368    }
369}
370
371static void
372memphis_renderer_set_property (GObject *object,
373    guint property_id,
374    const GValue *value,
375    GParamSpec *pspec)
376{
377  MemphisRenderer *self = MEMPHIS_RENDERER (object);
378  switch (property_id)
379    {
380      case PROP_RESOLUTION:
381        memphis_renderer_set_resolution (self, g_value_get_uint (value));
382        break;
383      case PROP_MAP:
384        memphis_renderer_set_map (self, g_value_get_object (value));
385        break;
386      case PROP_RULE_SET:
387        memphis_renderer_set_rules_set (self, g_value_get_object (value));
388        break;
389      case PROP_DEBUG_LEVEL:
390        memphis_renderer_set_debug_level (self, g_value_get_int (value));
391        break;
392      default:
393        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
394    }
395}
396
397static void
398memphis_renderer_class_init (MemphisRendererClass *klass)
399{
400  GObjectClass *object_class = G_OBJECT_CLASS (klass);
401
402  g_type_class_add_private (klass, sizeof (MemphisRendererPrivate));
403
404  object_class->get_property = memphis_renderer_get_property;
405  object_class->set_property = memphis_renderer_set_property;
406  object_class->dispose = memphis_renderer_dispose;
407  object_class->finalize = memphis_renderer_finalize;
408
409  /**
410  * MemphisRenderer:resolution:
411  *
412  * The tile resolution in pixel.
413  *
414  * Since: 0.1
415  */
416  g_object_class_install_property (object_class,
417      PROP_RESOLUTION,
418      g_param_spec_uint ("resolution",
419        "Tile resolution",
420        "The tile resolution in pixel",
421        8,
422        2048,
423        256,
424        G_PARAM_READWRITE));
425
426  /**
427  * MemphisRenderer:map:
428  *
429  * A MemphisMap.
430  *
431  * Since: 0.1
432  */
433  g_object_class_install_property (object_class,
434      PROP_MAP,
435      g_param_spec_object ("map",
436        "A MemphisMap",
437        "OSM map data",
438        MEMPHIS_TYPE_MAP,
439        G_PARAM_READWRITE));
440
441  /**
442  * MemphisRenderer:rule-set:
443  *
444  * A MemphisRuleSet.
445  *
446  * Since: 0.1
447  */
448  g_object_class_install_property (object_class,
449      PROP_RULE_SET,
450      g_param_spec_object ("rule-set",
451        "A MemphisRuleSet",
452        "Memphis rendering rules",
453        MEMPHIS_TYPE_RULE_SET,
454        G_PARAM_READWRITE));
455
456  /**
457  * MemphisRenderer:debug-level:
458  *
459  * The debug level of the renderer.
460  *
461  * Since: 0.1
462  */
463  g_object_class_install_property (object_class,
464      PROP_DEBUG_LEVEL,
465      g_param_spec_int ("debug-level",
466        "Debug level",
467        "The renderer debug level",
468        0,
469        2,
470        1,
471        G_PARAM_READWRITE));
472
473}
474
475static void
476memphis_renderer_init (MemphisRenderer *self)
477{
478  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
479  priv->map = NULL;
480  priv->rules = NULL;
481  priv->resolution = 256;
482  priv->debug_level = 1;
483}
484
485gint
486memphis_renderer_get_row_count (MemphisRenderer *self, guint zoom_level)
487{
488  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), -1);
489
490  return (1 << zoom_level);
491}
492
493gint
494memphis_renderer_get_column_count (MemphisRenderer *self, guint zoom_level)
495{
496  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), -1);
497
498  return (1 << zoom_level);
499}
500
501gint
502memphis_renderer_get_min_x_tile (MemphisRenderer *self, guint zoom_level)
503{
504  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), -1);
505
506  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
507  osmFile *osm;
508
509  if (!MEMPHIS_IS_MAP (priv->map))
510    return -1;
511
512  osm = memphis_map_get_osmFile (priv->map);
513  if (osm == NULL)
514    return -1;
515
516  return lon2tilex (osm->minlon, zoom_level);
517}
518
519gint
520memphis_renderer_get_max_x_tile (MemphisRenderer *self, guint zoom_level)
521{
522  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), -1);
523 
524  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
525  osmFile *osm;
526
527  if (!MEMPHIS_IS_MAP (priv->map))
528    return -1;
529
530  osm = memphis_map_get_osmFile (priv->map);
531  if (osm == NULL)
532    return -1;
533
534  return lon2tilex (osm->maxlon, zoom_level);
535}
536
537gint
538memphis_renderer_get_min_y_tile (MemphisRenderer *self, guint zoom_level)
539{
540  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), -1);
541 
542  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
543  osmFile *osm;
544
545  if (!MEMPHIS_IS_MAP (priv->map))
546    return -1;
547
548  osm = memphis_map_get_osmFile (priv->map);
549  if (osm == NULL)
550    return -1;
551
552  return lat2tiley (osm->maxlat, zoom_level);
553}
554
555gint
556memphis_renderer_get_max_y_tile (MemphisRenderer *self, guint zoom_level)
557{
558  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), -1);
559 
560  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
561  osmFile *osm;
562
563  if (!MEMPHIS_IS_MAP (priv->map))
564    return -1;
565
566  osm = memphis_map_get_osmFile (priv->map);
567  if (osm == NULL)
568    return -1;
569
570  return lat2tiley (osm->minlat, zoom_level);
571}
572
573gboolean
574memphis_renderer_tile_has_data (MemphisRenderer *self, guint x, guint y,
575    guint zoom_level)
576{
577  g_return_val_if_fail (MEMPHIS_IS_RENDERER (self), FALSE);
578
579  gint minx, miny, maxx, maxy;
580  MemphisRendererPrivate *priv = MEMPHIS_RENDERER_GET_PRIVATE (self);
581  osmFile *osm;
582
583  if (!MEMPHIS_IS_MAP (priv->map))
584    return FALSE;
585
586  osm = memphis_map_get_osmFile (priv->map);
587  if (osm == NULL)
588    return FALSE;
589
590  minx = lon2tilex (osm->minlon, zoom_level);
591  miny = lat2tiley (osm->minlat, zoom_level);
592  maxx = lon2tilex (osm->maxlon, zoom_level);
593  maxy = lat2tiley (osm->maxlat, zoom_level);
594
595  if (x < minx || x > maxx || y < miny || y > maxy)
596    return FALSE;
597 
598  return TRUE;
599}
600
601/*
602 * function: drawPath
603 * @info data of this render session
604 * @nodes Liked list of osmNode's
605 *
606 * This function is used to prepare a Path.
607 */
608static void drawPath (renderInfo *info, GSList *nodes) {
609  GSList *iter;
610  osmNode *nd;
611  coordinates xy;
612  MemphisRendererPrivate *p = info->priv;
613
614  if (G_UNLIKELY (p->debug_level > 1))
615    g_fprintf (stdout, "drawPath\n");
616
617  iter = nodes;
618  nd = iter->data;
619  xy = coord2xy (nd->lat, nd->lon, info->zoom_level, p->resolution);
620  cairo_move_to (info->cr, xy.x - info->offset.x,
621                           xy.y - info->offset.y);
622
623  iter = g_slist_next(iter);
624  while (iter) {
625    nd = iter->data;
626    xy = coord2xy (nd->lat, nd->lon, info->zoom_level, p->resolution);
627    cairo_line_to (info->cr, xy.x - info->offset.x,
628                             xy.y - info->offset.y);
629    iter = g_slist_next (iter);
630  }
631}
632
633/*
634 * function: strokePath
635 * @info data of this render session
636 *
637 * This function is stroke all current path without drawing anithing.
638 */
639static void strokePath (renderInfo *info) {
640  if (G_UNLIKELY (info->priv->debug_level > 1))
641    g_fprintf (stdout,"strokePath\n");
642
643  cairo_set_line_width (info->cr, 0);
644  cairo_stroke (info->cr);
645}
646
647/*
648 * function: drawPolygone
649 * @info data of this render session
650 * @draw a cfgDraw
651 *
652 * This function fill the prepared paths with the configured color.
653 */
654static void drawPolygone (renderInfo *info, cfgDraw *draw) {
655  if (G_UNLIKELY (info->priv->debug_level > 1))
656    g_fprintf (stdout, "drawPolygone\n");
657
658  cairo_surface_t *image = NULL;
659  cairo_pattern_t *pattern = NULL;
660
661  if (draw->pattern) {
662    char *filename;
663
664    /* TODO ast: the pattern may be cached, e.g. using a GCache structure */
665
666    filename = g_strdup_printf ("pattern/%s.png", draw->pattern);
667    image = cairo_image_surface_create_from_png (filename);
668    if (cairo_surface_status (image) != CAIRO_STATUS_SUCCESS) {
669      g_warning ("pattern '%s' not found\n", filename);
670      g_free (filename);
671      return;
672    }
673    g_free (filename);
674
675    pattern = cairo_pattern_create_for_surface (image);
676    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
677    cairo_surface_destroy (image);
678  }
679
680  cairo_set_fill_rule (info->cr, CAIRO_FILL_RULE_EVEN_ODD);
681
682  if (pattern)
683    cairo_set_source (info->cr, pattern);
684  else
685    cairo_set_source_rgb (info->cr, (double)draw->color[0]/255.0,
686                                    (double)draw->color[1]/255.0,
687                                    (double)draw->color[2]/255.0);
688
689  cairo_fill_preserve (info->cr);
690
691  if (pattern)
692    cairo_pattern_destroy (pattern);
693}
694
695/*
696 * function: drawLine
697 * @info data of this render session
698 * @draw a cfgDraw
699 *
700 * This function draw the prepared paths with the configured color.
701 */
702static void drawLine (renderInfo *info, cfgDraw *draw) {
703  if (G_UNLIKELY (info->priv->debug_level > 1))
704    g_fprintf (stdout, "drawLine\n");
705
706  cairo_set_line_cap (info->cr, CAIRO_LINE_CAP_ROUND);
707  cairo_set_line_join (info->cr, CAIRO_LINE_JOIN_ROUND);
708  cairo_set_line_width (info->cr, draw->width * LINESIZE (info->zoom_level));
709
710  cairo_set_source_rgb (info->cr, (double)draw->color[0]/255.0,
711                                  (double)draw->color[1]/255.0,
712                                  (double)draw->color[2]/255.0);
713  cairo_stroke_preserve(info->cr);
714}
715
716/*
717 * function: drawText
718 * @info data of this render session
719 * @draw a cfgDraw
720 *
721 * This function draw the given text along the current path.
722 */
723static void drawText (renderInfo *info, char *text, cfgDraw *draw) {
724  if (G_UNLIKELY (info->priv->debug_level > 1))
725    g_fprintf(stdout, "drawText\n");
726
727  cairo_select_font_face (info->cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
728                                            CAIRO_FONT_WEIGHT_NORMAL);
729  cairo_set_source_rgb (info->cr, (double)draw->color[0]/255.0,
730                                  (double)draw->color[1]/255.0,
731                                  (double)draw->color[2]/255.0);
732  cairo_set_font_size (info->cr, draw->width * LINESIZE (info->zoom_level));
733  textPath (info->cr, text);
734}
735
736/*
737 * function: stringInStrings
738 *
739 * Check if string is an strings.
740 */
741static compare_result_e stringInStrings(char *string, char **strings,
742      gint8 debug_level) {
743  if (G_UNLIKELY (debug_level > 1))
744    g_fprintf(stdout, "stringInStrings\n");
745  compare_result_e r = TAG_CMP_NOT_EQUAL;
746  while (*strings != NULL) {
747    if (string == *strings) {
748      return TAG_CMP_EQUAL;
749    }
750    if(strcmp(*strings, "*") == 0)
751      r = TAG_CMP_ANY;
752    if(strcmp(*strings, "~") == 0)
753      r = TAG_CMP_MISSING;
754
755    strings++;
756  }
757  return r;
758}
759
760/*
761 * function: matchRule
762 *
763 * Check if a element matchs a rule.
764 */
765static int matchRule (cfgRule *rule, osmTag *tag, gint8 debug_level) {
766  int k, v;
767
768  if (G_UNLIKELY (debug_level > 1))
769    g_fprintf(stdout, "matchRule\n");
770
771  while(tag) {
772      k = stringInStrings (tag->key, rule->key, debug_level);
773      v = stringInStrings (tag->value, rule->value, debug_level);
774
775      if (k == TAG_CMP_EQUAL && v == TAG_CMP_EQUAL)
776        return TRUE;
777      if (k == TAG_CMP_EQUAL && v == TAG_CMP_ANY)
778      return TRUE;
779      if (k == TAG_CMP_NOT_EQUAL && v == TAG_CMP_MISSING)
780        return TRUE;
781
782      tag = tag->next;
783  }
784  return FALSE;
785}
786
787/*
788 * function: checkRule
789 *
790 * Check if a element match to a rule and all it's parent.
791 */
792static int checkRule (cfgRule *rule, osmTag *tag, short int type,
793    gint8 debug_level) {
794  if (G_UNLIKELY (debug_level > 1))
795    g_fprintf(stdout, "checkRule\n");
796
797  int not;
798  cfgRule *iter;
799
800  if (rule->nparent) {
801    iter = rule->nparent;
802    not = TRUE;
803  } else {
804    iter = rule->parent;
805    not = FALSE;
806  }
807
808  while (iter) {
809
810      if (matchRule(iter, tag, debug_level) == not) {
811        return 0;
812      }
813
814      if (iter->nparent) {
815        iter = iter->nparent;
816        not = TRUE;
817      } else {
818        iter = iter->parent;
819        not = FALSE;
820      }
821  }
822
823  if(matchRule(rule, tag, debug_level)) {
824    return 1;
825  } else {
826    return -1;
827  }
828}
829
830static void renderPaths (renderInfo *info, int layer,
831        cfgRule *rule, cfgDraw *draw) {
832  int paths = 0;
833  osmWay *way;
834  MemphisRendererPrivate *p = info->priv;
835  osmFile *osm = memphis_map_get_osmFile (p->map); // FIXME: speed
836
837  // Loop through ways for
838  LIST_FOREACH(way, osm->ways) {
839    //Only objects on current layer
840    if (way->layer != layer)
841      continue;
842
843    if ( checkRule(rule, way->tag, WAY, p->debug_level) == 1) {
844      drawPath(info, way->nd);
845      paths++;
846    }
847  }
848  if (paths) {
849      while(draw) {
850          if (draw->minzoom > info->zoom_level || draw->maxzoom < info->zoom_level) {
851              draw = draw->next;
852              continue;
853          }
854          switch(draw->type) {
855              case POLYGONE:
856                  drawPolygone(info, draw);
857                  break;
858              case LINE:
859                  drawLine(info, draw);
860                  break;
861              case TEXT: break;   /* ignore */
862          }
863          draw = draw->next;
864      }
865  }
866  strokePath (info);
867}
868
869static void renderText (renderInfo *info, int layer,
870    cfgRule *rule, cfgDraw *draw) {
871  osmWay *way;
872  MemphisRendererPrivate *p = info->priv;
873  osmFile *osm = memphis_map_get_osmFile (p->map); // FIXME: speed
874
875  while (draw) {
876      if (draw->type == TEXT) {
877          if (draw->minzoom <= info->zoom_level && info->zoom_level <= draw->maxzoom) {
878              LIST_FOREACH(way, osm->ways) {
879                  //Only objects on current layer
880                  if (way->layer != layer || way->name == NULL)
881                      continue;
882
883                  if (checkRule(rule, way->tag, WAY, p->debug_level) == 1) {
884                      drawPath(info, way->nd);
885                      drawText(info, way->name, draw);
886                  }
887              }
888
889          }
890          break;
891      }
892      draw = draw->next;
893  }
894  strokePath (info);
895}
896
897/*
898 * function: renderCairo
899 */
900static int renderCairo (renderInfo *info) {
901  int layer;
902  MemphisRendererPrivate *p = info->priv;
903  cfgRules *ruleset = memphis_rule_set_get_cfgRules (p->rules);
904
905  if (p->debug_level > 1)
906    g_fprintf (stdout, "renderCairoRun\n");
907
908  // Vars used while looping through data
909  cfgRule     *rule;
910
911  // Start checking osm from bottom layer.
912  for (layer = -5; layer <= 5; layer++) {
913
914      if (p->debug_level > 0) {
915          g_fprintf(stdout,"\r Cairo drawing z%i Layer % 2i", info->zoom_level, layer);
916          fflush(stdout);
917      }
918
919      // Process Rule by Rule
920      LIST_FOREACH(rule, ruleset->rule) {
921
922          if(rule->draw != NULL) { // Draw Match first
923              renderPaths(info, layer, rule, rule->draw);
924
925              // Text Rendering
926              renderText(info, layer, rule, rule->draw);
927          }
928          if (rule->ndraw != NULL) { // Draw Else after
929              renderPaths(info, layer, rule, rule->ndraw);
930          }
931      }
932  }
933
934  if (p->debug_level > 0)
935      g_fprintf (stdout, "\r Cairo drawing done\n");
936
937  return 0;
938}
Note: See TracBrowser for help on using the repository browser.