Hi,

the current scheme for mapping public transportation (http://wiki.openstreetmap.org/wiki/Proposed_features/Public_Transport) uses nested relations. The primary information about a line (reference, operator etc.) is stored in a master relation which contains relations for the different directions or variants.

When osm2pgsql imports such relations it converts them into lines with all the tags attached. But in this case the information from the master relation is not forwarded. Several osm-based maps showing public transportation thus do no longer show the line number along the route displayed (cf. the recent discussion in German on http://wiki.openstreetmap.org/wiki/Talk:%C3%96pnvkarte#Relations_aus_Routen) as soon as people enter them according to the new scheme.

I dug into the sources and found a solution which is attached as a patch. As I am certainly no expert in osm2pgsql's database handling I am open for any comments. If a solution along these lines could be integrated (maybe guarded by an option) this would restore the functionality of the maps mentioned without inspiring people to attach all tags at all relations just to get rendering working.


--
Michael

Index: pgsql.c
===================================================================
--- pgsql.c     (revision 27851)
+++ pgsql.c     (working copy)
@@ -11,7 +11,8 @@
 void escape(char *out, int len, const char *in)
 { 
     /* Apply escaping of TEXT COPY data
-    Escape: backslash itself, newline, carriage return, and the current 
delimiter character (tab)
+    Escape: backslash itself, newline, carriage return, current delimiter 
character (tab),
+    and the single quote
     file:///usr/share/doc/postgresql-8.1.8/html/sql-copy.html
     */
     int count = 0; 
@@ -29,6 +30,7 @@
             case '\r': *out++ = '\\'; *out++ = '\r'; count+= 2; break;
             case '\t': *out++ = '\\'; *out++ = '\t'; count+= 2; break;
       //    case   11: *out++ = '\\'; *out++ = '\v'; count+= 2; break;
+            case '\'': *out++ = '\\'; *out++ = '\''; count+= 2; break;
             default:   *out++ = *in; count++; break;
         }
         in++;
Index: output-pgsql.c
===================================================================
--- output-pgsql.c      (revision 27851)
+++ output-pgsql.c      (working copy)
@@ -121,6 +121,7 @@
 static int pgsql_delete_way_from_output(osmid_t osm_id);
 static int pgsql_delete_relation_from_output(osmid_t osm_id);
 static int pgsql_process_relation(osmid_t id, struct member *members, int 
member_count, struct keyval *tags, int exists);
+static void pgsql_pause_copy(struct s_table *table);
 
 void read_style_file( const char *filename )
 {
@@ -406,8 +407,51 @@
     updateItem(tags, "name", out);
 }
 
+/* returns 1 if key is exported, -1 if key is deleted, 0 otherwise */
+static int key_is_in_export_list(char *key, enum OsmType list)
+{
+    for (int i = 0; i < exportListCount[list]; ++i) {
+        if (! strcmp(key, exportList[list][i].name)) {
+            if (exportList[list][i].flags & FLAG_DELETE)
+              return -1;
+            else
+              return 1;
+        }
+    }
+    return 0;
+}
 
+/* Attach the tags to the ways generated out of the member relations unless 
+   they are already present */
+static void transfer_master_tags(struct keyval *tags, osmid_t member)
+{
+    struct keyval *p = tags->next;
+    char value[128];
 
+    if (tags == NULL)
+      return;
+    pgsql_pause_copy(&tables[t_line]);
+
+    while (p != tags) {
+      if (strcmp(p->key, "type") && strcmp(p->key, "route_master")) {
+
+        int export_flag = key_is_in_export_list(p->key, OSMTYPE_WAY);
+        escape (value, 127, p->value);
+
+        if (export_flag == 1) {
+          pgsql_exec(tables[t_line].sql_conn, PGRES_COMMAND_OK, 
+                     "UPDATE %s SET %s = \'%s\' WHERE %s IS NULL AND osm_id = 
-%d ;\n", 
+                     tables[t_line].name, p->key, value, p->key, member);
+        } else if (export_flag == 0) {
+          pgsql_exec(tables[t_line].sql_conn, PGRES_COMMAND_OK, 
+                     "UPDATE %s SET tags = tags || (\'%s\'=>\'%s\') WHERE NOT 
tags ? \'%s\' AND osm_id = -%d ;\n", 
+                     tables[t_line].name, p->key, value, p->key, member);
+        }
+      }
+      p = p->next;
+    }
+}
+
 static void pgsql_out_cleanup(void)
 {
     int i;
@@ -1614,15 +1658,26 @@
   for( i=0; i<member_count; i++ )
   {
     /* Need to handle more than just ways... */
-    if( members[i].type != OSMTYPE_WAY )
+    if( members[i].type == OSMTYPE_NODE )
         continue;
 
     initList(&(xtags[count]));
-    if( Options->mid->ways_get( members[i].id, &(xtags[count]), 
&(xnodes[count]), &(xcount[count]) ) )
+    if( members[i].type == OSMTYPE_WAY )
+    {
+      if( Options->mid->ways_get( members[i].id, &(xtags[count]), 
&(xnodes[count]), &(xcount[count]) ) )
+        continue;
+
+      xid[count] = members[i].id;
+      xrole[count] = members[i].role;
+      count++;
+    }
+    /* attach tags from a route_master (except those classifying it as a 
master)
+       to the ways generated out of the member relations */
+    else if( ( members[i].type == OSMTYPE_RELATION ) && ( !strcmp( 
getItem(tags, "type"), "route_master" ) ) )
+    {
+      transfer_master_tags( tags, members[i].id );
       continue;
-    xid[count] = members[i].id;
-    xrole[count] = members[i].role;
-    count++;
+    }
   }
   xnodes[count] = NULL;
   xcount[count] = 0;

_______________________________________________
dev mailing list
dev@openstreetmap.org
http://lists.openstreetmap.org/listinfo/dev

Reply via email to