source: trunk/src/memphis-rule-set.c @ 213

Last change on this file since 213 was 213, checked in by simon, 4 years ago

Documentation fix

File size: 18.0 KB
Line 
1/*
2 * Memphis - Cairo Rederer for OSM in C
3 * Copyright (C) 2009  Simon Wenner <simon@wenner.ch>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20/**
21 * SECTION:memphis-rule-set
22 * @short_description: Defines drawing rules for the renderer.
23 *
24 * This Object defines drawing rules for a #MemphisRenderer. The rules
25 * can be loaded from an XML file or can they be defined during
26 * execution time.
27 */
28
29#include <string.h>
30#include "mlib.h"
31#include "ruleset.h"
32#include "memphis-private.h"
33#include "memphis-rule-set.h"
34#include "memphis-data-pool.h"
35
36G_DEFINE_TYPE (MemphisRuleSet, memphis_rule_set, G_TYPE_OBJECT)
37
38#define MEMPHIS_RULE_SET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MEMPHIS_TYPE_RULE_SET, MemphisRuleSetPrivate))
39
40enum
41{
42  PROP_0,
43};
44
45typedef struct _MemphisRuleSetPrivate MemphisRuleSetPrivate;
46
47struct _MemphisRuleSetPrivate {
48  cfgRules *ruleset;
49};
50
51static void
52memphis_rule_set_get_property (GObject *object, guint property_id,
53                              GValue *value, GParamSpec *pspec)
54{
55  //MemphisRuleSet *self = MEMPHIS_RULE_SET (object);
56  //MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
57  switch (property_id)
58  {
59    default:
60      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
61  }
62}
63
64static void
65memphis_rule_set_set_property (GObject *object, guint property_id,
66                              const GValue *value, GParamSpec *pspec)
67{
68  //MemphisRuleSet *self = MEMPHIS_RULE_SET (object);
69  switch (property_id)
70  {
71    default:
72      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
73  }
74}
75
76static void
77memphis_rule_set_finalize (GObject *object)
78{
79  MemphisRuleSet *self = MEMPHIS_RULE_SET (object);
80  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
81
82  if (priv->ruleset != NULL)
83    rulesetFree(priv->ruleset);
84 
85  G_OBJECT_CLASS (memphis_rule_set_parent_class)->finalize (object);
86}
87
88static void
89memphis_rule_set_class_init (MemphisRuleSetClass *klass)
90{
91  GObjectClass *object_class = G_OBJECT_CLASS (klass);
92
93  g_type_class_add_private (klass, sizeof (MemphisRuleSetPrivate));
94
95  object_class->get_property = memphis_rule_set_get_property;
96  object_class->set_property = memphis_rule_set_set_property;
97  object_class->finalize = memphis_rule_set_finalize;
98}
99
100static void
101memphis_rule_set_init (MemphisRuleSet *self)
102{
103  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
104  priv->ruleset = NULL;
105}
106
107/**
108 * memphis_rule_set_new:
109 *
110 * Returns: a new #MemphisRuleSet whithout any rules.
111 *
112 * Since: 0.1
113 */
114MemphisRuleSet*
115memphis_rule_set_new ()
116{
117  MemphisRuleSet* self = g_object_new (MEMPHIS_TYPE_RULE_SET, NULL);
118  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
119  priv->ruleset = rulesetNew ();
120  return self;
121}
122
123/**
124 * memphis_rule_set_load_from_file:
125 * @rules: a #MemphisRuleSet
126 * @filename: a path to a rules file
127 * @error: a pointer to a GError or NULL
128 *
129 * Load rules from an XML file.
130 *
131 * Since: 0.2
132 */
133void
134memphis_rule_set_load_from_file (MemphisRuleSet *rules,
135    const gchar *filename,
136    GError **error)
137{
138  g_return_if_fail (MEMPHIS_IS_RULE_SET (rules) && filename != NULL);
139
140  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (rules);
141  if (priv->ruleset != NULL)
142    rulesetFree (priv->ruleset);
143
144  priv->ruleset = rulesetRead (filename, error);
145}
146
147/**
148 * memphis_rule_set_load_from_data:
149 * @rules: a #MemphisRuleSet
150 * @data: a character array with rules XML data
151 * @size: the size of the array
152 * @error: a pointer to a GError or NULL
153 *
154 * Load rules data from an XML file.
155 *
156 * Since: 0.2
157 */
158void
159memphis_rule_set_load_from_data (MemphisRuleSet *rules,
160    const gchar *data,
161    guint size,
162    GError **error)
163{
164  g_return_if_fail (MEMPHIS_IS_RULE_SET (rules) && data != NULL);
165
166  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (rules);
167  if (priv->ruleset != NULL)
168    rulesetFree (priv->ruleset);
169
170  priv->ruleset = rulesetRead_from_buffer (data, size, error);
171}
172
173/**
174 * memphis_rule_set_free:
175 * @rules: a #MemphisRuleSet
176 *
177 * Frees the memory of a #MemphisRuleSet.
178 *
179 * Since: 0.1
180 */
181void
182memphis_rule_set_free (MemphisRuleSet *rules)
183{
184  g_return_if_fail (MEMPHIS_IS_RULE_SET (rules));
185
186  g_object_unref (G_OBJECT (rules));
187}
188
189/**
190 * memphis_rule_set_set_bg_color:
191 * @rules: a #MemphisRuleSet
192 * @r: red color component
193 * @g: green color component
194 * @b: blue color component
195 * @a: transparency
196 *
197 * Sets the background color and transparency rule.
198 *
199 * Since: 0.1
200 */
201void
202memphis_rule_set_set_bg_color (MemphisRuleSet *self,
203    guint8 r,
204    guint8 g,
205    guint8 b,
206    guint8 a)
207{
208  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
209
210  priv->ruleset->background[0] = r;
211  priv->ruleset->background[1] = g;
212  priv->ruleset->background[2] = b;
213  priv->ruleset->background[3] = a;
214}
215
216/**
217 * memphis_rule_set_get_bg_color:
218 * @rules: a #MemphisRuleSet
219 * @r: (out): red color component
220 * @g: (out): green color component
221 * @b: (out): blue color component
222 * @a: (out): transparency
223 *
224 * Assigns the background color and the transparency of the background
225 * to r, g, b and a.
226 *
227 * Since: 0.1
228 */
229void
230memphis_rule_set_get_bg_color (MemphisRuleSet *self,
231    guint8 *r,
232    guint8 *g,
233    guint8 *b,
234    guint8 *a)
235{
236  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
237
238  *r = priv->ruleset->background[0];
239  *g = priv->ruleset->background[1];
240  *b = priv->ruleset->background[2];
241  *a = priv->ruleset->background[3];
242}
243
244/**
245 * memphis_rule_set_get_rule_ids:
246 * @rules: a #MemphisRuleSet
247 *
248 * Returns: (transfer full): a list of rule id strings.
249 * Free the list with g_list_free when done.
250 *
251 * These strings have the following form:
252 * key1|key2|...|keyN:value1|value2|...|valueM
253 *
254 * Example: "waterway:river|stream|canal"
255 *
256 * Since: 0.1
257 */
258GList *
259memphis_rule_set_get_rule_ids (MemphisRuleSet *self)
260{
261  g_return_val_if_fail (MEMPHIS_IS_RULE_SET (self), NULL);
262
263  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
264
265  GList *list = NULL;
266  cfgRule *curr = priv->ruleset->rule;
267  while (curr != NULL)
268   {
269     if (curr->draw != NULL)
270      {
271        gchar *keys = g_strjoinv ("|", curr->key);
272        gchar *values = g_strjoinv ("|", curr->value);
273        gchar *id = g_strconcat (keys, ":", values, NULL);
274        list = g_list_append (list, id);
275        g_free (keys);
276        g_free (values);
277      }
278      curr = curr->next;
279   }
280   return list;
281}
282
283static MemphisRule *
284rule_new_from_cfgRule (cfgRule *curr)
285{
286  MemphisRule *rule;
287  rule = memphis_rule_new ();
288  rule->keys = g_strdupv (curr->key);
289  rule->values = g_strdupv (curr->value);
290  switch (curr->type)
291    {
292      case (WAY):
293        rule->type = MEMPHIS_RULE_TYPE_WAY;
294        break;
295      case (NODE):
296        rule->type = MEMPHIS_RULE_TYPE_NODE;
297        break;
298      case (RELATION):
299        rule->type = MEMPHIS_RULE_TYPE_RELATION;
300        break;
301      default:
302        rule->type = MEMPHIS_RULE_TYPE_UNKNOWN;
303    }
304
305  cfgDraw *drw = curr->draw;
306  gboolean line_seen = FALSE;
307  while (drw != NULL)
308    {
309      if (drw->type == POLYGONE)
310        {
311          rule->polygon = g_slice_new0 (MemphisRuleAttr);
312          rule->polygon->color_red = drw->color[0];
313          rule->polygon->color_green = drw->color[1];
314          rule->polygon->color_blue = drw->color[2];
315          rule->polygon->color_alpha = 255;
316          rule->polygon->z_min = drw->minzoom;
317          rule->polygon->z_max = drw->maxzoom;
318          rule->polygon->style = NULL;
319          // TODO support pattern
320        }
321      else if (drw->type == LINE)
322        {
323          if (line_seen) {
324            /* line with border */
325            rule->border = g_slice_new0 (MemphisRuleAttr);
326            rule->border->color_red = rule->line->color_red;
327            rule->border->color_green = rule->line->color_green;
328            rule->border->color_blue = rule->line->color_blue;
329            rule->border->color_alpha = rule->line->color_alpha;
330            rule->border->size = (rule->line->size - drw->width) * 0.5;
331            rule->border->z_min = rule->line->z_min;
332            rule->border->z_max = rule->line->z_max;
333            rule->border->style = NULL;
334
335            rule->line->color_red = drw->color[0];
336            rule->line->color_green = drw->color[1];
337            rule->line->color_blue = drw->color[2];
338            rule->line->color_alpha = 255;
339            rule->line->size = drw->width;
340            rule->line->z_min = drw->minzoom;
341            rule->line->z_max = drw->maxzoom;
342            rule->line->style = NULL;
343           
344          } else {
345            /* only a single line */
346            rule->line = g_slice_new0 (MemphisRuleAttr);
347            rule->line->color_red = drw->color[0];
348            rule->line->color_green = drw->color[1];
349            rule->line->color_blue = drw->color[2];
350            rule->line->color_alpha = 255;
351            rule->line->size = drw->width;
352            rule->line->z_min = drw->minzoom;
353            rule->line->z_max = drw->maxzoom;
354            rule->line->style = NULL;
355            line_seen = TRUE;
356          }
357        }
358      else if (drw->type == TEXT)
359        {
360          rule->text = g_slice_new0 (MemphisRuleAttr);
361          rule->text->color_red = drw->color[0];
362          rule->text->color_green = drw->color[1];
363          rule->text->color_blue = drw->color[2];
364          rule->text->color_alpha = 255;
365          rule->text->size = drw->width;
366          rule->text->z_min = drw->minzoom;
367          rule->text->z_max = drw->maxzoom;
368          rule->text->style = NULL;
369        }
370      drw = drw->next;
371    }
372  /*
373  cfgDraw *ndrw = curr->ndraw;
374  while (ndrw != NULL)
375    {
376      g_print ("NDRAW: %d\n", ndrw->type);
377      ndrw = ndrw->next;
378    }
379  */
380
381  return rule;
382}
383
384static void
385add_new_cfgDraws (cfgRule *out, MemphisRule *rule)
386{
387  cfgDraw *tmp;
388  cfgDraw *drw = NULL;
389
390  if (rule->polygon != NULL)
391    {
392      tmp = g_new (cfgDraw, 1);
393      tmp->next = drw;
394      tmp->type = POLYGONE;
395      tmp->minzoom = rule->polygon->z_min;
396      tmp->maxzoom = rule->polygon->z_max;
397      tmp->color[0] = rule->polygon->color_red;
398      tmp->color[1] = rule->polygon->color_green;
399      tmp->color[2] = rule->polygon->color_blue;
400      drw = tmp;
401    }
402  if (rule->line != NULL)
403    {
404      tmp = g_new (cfgDraw, 1);
405      tmp->next = drw;
406      tmp->type = LINE;
407      tmp->minzoom = rule->line->z_min;
408      tmp->maxzoom = rule->line->z_max;
409      tmp->color[0] = rule->line->color_red;
410      tmp->color[1] = rule->line->color_green;
411      tmp->color[2] = rule->line->color_blue;
412      tmp->width = rule->line->size;
413      drw = tmp;
414    }
415  if (rule->border != NULL)
416    {
417      tmp = g_new (cfgDraw, 1);
418      tmp->next = drw;
419      tmp->type = LINE;
420      tmp->minzoom = rule->border->z_min;
421      tmp->maxzoom = rule->border->z_max;
422      tmp->color[0] = rule->border->color_red;
423      tmp->color[1] = rule->border->color_green;
424      tmp->color[2] = rule->border->color_blue;
425      if (rule->line != NULL)
426        tmp->width = 2.0 * rule->border->size + rule->line->size;
427      else
428        tmp->width = rule->border->size; /* polygon border */
429      drw = tmp;
430    }
431  if (rule->text != NULL)
432    {
433      tmp = g_new (cfgDraw, 1);
434      tmp->next = drw;
435      tmp->type = TEXT;
436      tmp->minzoom = rule->text->z_min;
437      tmp->maxzoom = rule->text->z_max;
438      tmp->color[0] = rule->text->color_red;
439      tmp->color[1] = rule->text->color_green;
440      tmp->color[2] = rule->text->color_blue;
441      tmp->width = rule->text->size;
442      drw = tmp;
443    }
444    out->draw = drw;
445}
446
447static cfgRule *
448cfgRule_new_from_rule (MemphisRule *rule)
449{
450  int c, len;
451  MemphisDataPool *pool = memphis_data_pool_new ();
452  cfgRule *new = g_new (cfgRule, 1);
453
454  switch (rule->type)
455    {
456      case (MEMPHIS_RULE_TYPE_WAY):
457        new->type = WAY;
458        break;
459      case (MEMPHIS_RULE_TYPE_NODE):
460        new->type = NODE;
461        break;
462      case (MEMPHIS_RULE_TYPE_RELATION):
463        new->type = RELATION;
464        break;
465      default:
466        new->type = 0;
467    }
468
469  new->value = g_strdupv (rule->values);
470  len = g_strv_length (new->value);
471  for(c = 0; c < len; c++)
472    {
473      char *tmp = new->value[c];
474      new->value[c] = m_string_chunk_get(pool->stringChunk,
475                                         pool->stringTree, tmp);
476      g_free(tmp);
477    }
478  new->key = g_strdupv (rule->keys);
479  len = g_strv_length(new->key);
480  for(c = 0; c < len; c++)
481    {
482      char *tmp = new->key[c];
483      new->key[c] = m_string_chunk_get(pool->stringChunk,
484                                       pool->stringTree, tmp);
485      g_free(tmp);
486    }
487
488  g_object_unref (pool);
489
490  new->parent = NULL;
491  new->nparent = NULL;
492  new->next = NULL;
493  new->draw = NULL;
494  new->ndraw = NULL;
495
496  add_new_cfgDraws (new, rule);
497
498  return new;
499}
500
501static cfgRule *
502search_rule (cfgRule *rules, gchar **keys, gchar **values)
503{
504  int i;
505  gint len;
506  gboolean found = FALSE;
507  gboolean miss = FALSE;
508  gint num_keys = g_strv_length (keys);
509  gint num_values = g_strv_length (values);
510  cfgRule *curr = rules;
511
512  while (curr != NULL && !found)
513   {
514      miss = FALSE;
515      if (curr->draw != NULL)
516      {
517        len = g_strv_length (curr->key);
518        if (len != num_keys)
519          {
520            curr = curr->next;
521            continue;
522          }
523        for (i = 0; i < len; i++)
524          {
525            if (strcmp (curr->key[i], keys[i]) != 0)
526              miss = TRUE;
527          }
528
529        len = g_strv_length (curr->value);
530        if (len != num_values || miss)
531          {
532            curr = curr->next;
533            continue;
534          }
535        for (i = 0; i < len; i++)
536          {
537            if (strcmp (curr->value[i], values[i]) != 0)
538              miss = TRUE;
539          }
540        if (miss)
541          {
542            curr = curr->next;
543            continue;
544          }
545
546        found = TRUE;
547      }
548    else
549      {
550        curr = curr->next;
551      }
552   }
553
554  return curr;
555}
556
557/**
558 * memphis_rule_set_get_rule:
559 * @rules: a #MemphisRuleSet
560 * @id: an id string
561 *
562 * Returns: (allow-none): a #MemphisRule that has the given id string or NULL otherwise.
563 *
564 * Since: 0.1
565 */
566MemphisRule *
567memphis_rule_set_get_rule (MemphisRuleSet *self, const gchar *id)
568{
569  g_return_val_if_fail (MEMPHIS_IS_RULE_SET (self) && id != NULL, NULL);
570
571  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
572
573  gchar **tmp = g_strsplit (id, ":", -1);
574  gchar **keys = g_strsplit (tmp[0], "|", -1);
575  gchar **values = g_strsplit (tmp[1], "|", -1);
576  g_strfreev (tmp);
577
578  cfgRule *res = search_rule (priv->ruleset->rule, keys, values);
579
580  g_strfreev (keys);
581  g_strfreev (values);
582
583  if (res != NULL)
584    return rule_new_from_cfgRule (res);
585
586  return NULL;
587}
588
589/**
590 * memphis_rule_set_set_rule:
591 * @rules: a #MemphisRuleSet
592 * @rule: a #MemphisRule
593 *
594 * Adds the given rule to the rule set.
595 *
596 * Since: 0.1
597 */
598void
599memphis_rule_set_set_rule (MemphisRuleSet *self, MemphisRule *rule)
600{
601  g_return_if_fail (MEMPHIS_IS_RULE_SET (self) && MEMPHIS_RULE (rule));
602
603  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
604  cfgRule *res = search_rule (priv->ruleset->rule, rule->keys, rule->values);
605  cfgDraw *drw, *tmp;
606
607  if (res != NULL)
608    {
609      drw = res->draw;
610      /* delete old cfgDraw's */
611      while (drw != NULL)
612        {
613          tmp = drw;
614          drw = drw->next;
615          g_free (tmp);
616        }
617
618      /* Add new cfgDraw's */
619      add_new_cfgDraws (res, rule);
620    }
621  else
622    {
623      /* Append cfgRule at last position */
624      cfgRule *curr = priv->ruleset->rule;
625      while (curr->next != NULL)
626        curr = curr->next;
627
628      cfgRule *new = cfgRule_new_from_rule (rule);
629
630      curr->next = new;
631      priv->ruleset->cntRule++;
632    }
633}
634
635/**
636 * memphis_rule_set_remove_rule:
637 * @rules: a #MemphisRuleSet
638 * @id: an id string
639 *
640 * Removes the rule with the given id from the rules set.
641 *
642 * Returns: true if the rule could be found and removed.
643 *
644 * Since: 0.1
645 */
646gboolean
647memphis_rule_set_remove_rule (MemphisRuleSet *self, const gchar *id)
648{
649  g_return_val_if_fail (MEMPHIS_IS_RULE_SET (self) && id != NULL, FALSE);
650
651  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
652
653  gchar **tmp = g_strsplit (id, ":", -1);
654  gchar **keys = g_strsplit (tmp[0], "|", -1);
655  gchar **values = g_strsplit (tmp[1], "|", -1);
656  g_strfreev (tmp);
657
658  int i;
659  gint len;
660  gboolean found = FALSE;
661  gboolean miss = FALSE;
662  gint num_keys = g_strv_length (keys);
663  gint num_values = g_strv_length (values);
664  cfgRule *curr = priv->ruleset->rule;
665  cfgRule *prev = NULL;
666
667  while (curr != NULL && !found)
668   {
669      miss = FALSE;
670      len = g_strv_length (curr->key);
671      if (len != num_keys)
672        {
673          prev = curr;
674          curr = curr->next;
675          continue;
676        }
677      for (i = 0; i < len; i++)
678        {
679          if (strcmp (curr->key[i], keys[i]) != 0)
680            miss = TRUE;
681        }
682
683      len = g_strv_length (curr->value);
684      if (len != num_values || miss)
685        {
686          prev = curr;
687          curr = curr->next;
688          continue;
689        }
690      for (i = 0; i < len; i++)
691        {
692          if (strcmp (curr->value[i], values[i]) != 0)
693            miss = TRUE;
694        }
695      if (miss)
696        {
697          prev = curr;
698          curr = curr->next;
699          continue;
700        }
701
702      found = TRUE;
703   }
704
705  g_strfreev (keys);
706  g_strfreev (values);
707
708  if (curr == NULL)
709    return FALSE;
710
711  prev->next = curr->next;
712  cfgRuleFree (curr);
713  priv->ruleset->cntRule--;
714  return TRUE;
715}
716
717/* private shared functions */
718
719cfgRules *
720memphis_rule_set_get_cfgRules (MemphisRuleSet *self)
721{
722  g_assert (self != NULL);
723
724  MemphisRuleSetPrivate *priv = MEMPHIS_RULE_SET_GET_PRIVATE (self);
725
726  return priv->ruleset;
727}
Note: See TracBrowser for help on using the repository browser.