Add:maptool:Better resolving strategy for relations
authormartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Mon, 11 Jul 2011 12:35:45 +0000 (12:35 +0000)
committermartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Mon, 11 Jul 2011 12:35:45 +0000 (12:35 +0000)
git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@4623 ffa7fe5e-494d-0410-b361-a75ebd5db220

navit/navit/maptool/CMakeLists.txt
navit/navit/maptool/Makefile.am
navit/navit/maptool/itembin_buffer.c
navit/navit/maptool/maptool.h
navit/navit/maptool/osm.c
navit/navit/maptool/osm_relations.c [new file with mode: 0644]

index 6bee654..b01bdb4 100644 (file)
@@ -2,7 +2,7 @@
 if(BUILD_MAPTOOL)
    add_definitions( -DMODULE=maptool ${NAVIT_COMPILE_FLAGS})
    include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-   SET(MAPTOOL_SOURCE boundaries.c buffer.c ch.c coastline.c geom.c itembin.c itembin_buffer.c misc.c osm.c osm_o5m.c sourcesink.c tempfile.c tile.c zip.c osm_xml.c)
+   SET(MAPTOOL_SOURCE boundaries.c buffer.c ch.c coastline.c geom.c itembin.c itembin_buffer.c misc.c osm.c osm_o5m.c osm_relations.c sourcesink.c tempfile.c tile.c zip.c osm_xml.c)
    if(NOT MSVC)
        SET(MAPTOOL_SOURCE ${MAPTOOL_SOURCE} osm_protobuf.c osm_protobufdb.c generated-code/fileformat.pb-c.c generated-code/osmformat.pb-c.c google/protobuf-c/protobuf-c.c)
    endif(NOT MSVC)
index ca70bba..b88ed7f 100644 (file)
@@ -5,6 +5,6 @@ if !SUPPORT_ANDROID
 endif
 
 AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit @ZLIB_CFLAGS@ @POSTGRESQL_CFLAGS@ -DMODULE=maptool
-libmaptool_la_SOURCES = boundaries.c buffer.c ch.c coastline.c geom.c itembin.c itembin_buffer.c misc.c osm.c osm_o5m.c osm_psql.c osm_protobuf.c osm_protobufdb.c osm_xml.c sourcesink.c tempfile.c tile.c zip.c maptool.h generated-code/fileformat.pb-c.c generated-code/fileformat.pb-c.h generated-code/osmformat.pb-c.c generated-code/osmformat.pb-c.h google/protobuf-c/protobuf-c.c google/protobuf-c/protobuf-c.h google/protobuf-c/protobuf-c-private.h
+libmaptool_la_SOURCES = boundaries.c buffer.c ch.c coastline.c geom.c itembin.c itembin_buffer.c misc.c osm.c osm_o5m.c osm_psql.c osm_protobuf.c osm_protobufdb.c osm_relations.c osm_xml.c sourcesink.c tempfile.c tile.c zip.c maptool.h generated-code/fileformat.pb-c.c generated-code/fileformat.pb-c.h generated-code/osmformat.pb-c.c generated-code/osmformat.pb-c.h google/protobuf-c/protobuf-c.c google/protobuf-c/protobuf-c.h google/protobuf-c/protobuf-c-private.h
 maptool_SOURCES = maptool.c
 maptool_LDADD = libmaptool.la ../libnavit.la @NAVIT_LIBS@ @WORDEXP_LIBS@ @ZLIB_LIBS@ @POSTGRESQL_LIBS@ @CRYPTO_LIBS@ @INTLLIBS@ @LIBC_LIBS@
index 33894b2..8d7bece 100644 (file)
 
 static char buffer[800000];
 struct item_bin *item_bin=(struct item_bin *)(void *)buffer;
+static struct node_item *node_item=(struct node_item *)(void *)buffer;
+
+struct node_item *
+read_node_item(FILE *in)
+{
+       if (fread(node_item, sizeof(struct node_item), 1, in) != 1)
+               return NULL;
+       return node_item;
+}
 
 struct item_bin *
 read_item(FILE *in)
index a487b43..6a5e69a 100644 (file)
@@ -100,6 +100,15 @@ struct item_bin_sink {
        GList *sink_funcs;
 };
 
+struct node_item {
+       int id;
+       char ref_node;
+       char ref_way;
+       char ref_ref;
+       char dummy;
+       struct coord c;
+};
+
 struct zip_info;
 
 struct country_table;
@@ -205,6 +214,7 @@ void item_bin_write_match(struct item_bin *ib, enum attr_type type, enum attr_ty
 int item_bin_sort_file(char *in_file, char *out_file, struct rect *r, int *size);
 
 /* itembin_buffer.c */
+struct node_item *read_node_item(FILE *in);
 struct item_bin *read_item(FILE *in);
 struct item_bin *read_item_range(FILE *in, int *min, int *max);
 struct item_bin *init_item(enum item_type type);
@@ -298,6 +308,13 @@ int map_collect_data_osm_db(char *dbstr, struct maptool_osm *osm);
 int map_collect_data_osm_protobuf(FILE *in, struct maptool_osm *osm);
 int osm_protobufdb_load(FILE *in, char *dir);
 
+/* osm_relations.c */
+struct relations * relations_new(void);
+struct relations_func *relations_func_new(void (*func)(void *func_priv, void *relation_priv, struct item_bin *member, void *member_priv), void *func_priv);
+void relations_add_func(struct relations *rel, struct relations_func *func, void *relation_priv, void *member_priv, int type, osmid id);
+void relations_process(struct relations *rel, FILE *nodes, FILE *ways, FILE *relations);
+
+
 /* osm_xml.c */
 int osm_xml_get_attribute(char *xml, char *attribute, char *buffer, int buffer_size);
 void osm_xml_decode_entities(char *buffer);
index 045342e..4f41013 100644 (file)
@@ -1163,15 +1163,6 @@ osm_add_tag(char *k, char *v)
 
 int coord_count;
 
-struct node_item {
-       int id;
-       char ref_node;
-       char ref_way;
-       char ref_ref;
-       char dummy;
-       struct coord c;
-};
-
 static void
 extend_buffer(struct buffer *b)
 {
@@ -1975,6 +1966,179 @@ get_way(FILE *way, FILE *ways_index, struct coord *c, long long wayid, struct it
        return NULL;
 }
 
+struct turn_restriction {
+       osmid relid;
+       enum item_type type;
+       struct coord *c[3];
+       int c_count[3];
+};
+
+static void
+process_turn_restrictions_member(void *func_priv, void *relation_priv, struct item_bin *member, void *member_priv)
+{
+       int count,type=(long)member_priv;
+       struct turn_restriction *turn_restriction=relation_priv;
+       struct coord *c=(struct coord *)(member+1);
+       int ccount=member->clen/2;
+
+       if (member->type < type_line) 
+               count=1;        
+       else
+               count=2;
+       turn_restriction->c[type]=g_renew(struct coord, turn_restriction->c[type], turn_restriction->c_count[type]+count);
+       turn_restriction->c[type][turn_restriction->c_count[type]++]=c[0];
+       if (count > 1) 
+               turn_restriction->c[type][turn_restriction->c_count[type]++]=c[ccount-1];
+}
+
+static void
+process_turn_restrictions_fromto(struct turn_restriction *t, int type, struct coord **c)
+{
+       int i,j;
+       for (i = 0 ; i < t->c_count[type] ; i+=2) {
+               for (j = 0 ; j < t->c_count[1] ; j++) {
+                       if (coord_is_equal(t->c[type][i],t->c[1][j])) {
+                               c[0]=&t->c[type][i+1];
+                               c[1]=&t->c[type][i];
+                               return;
+                       }
+                       if (coord_is_equal(t->c[type][i+1],t->c[1][j])) {
+                               c[0]=&t->c[type][i];
+                               c[1]=&t->c[type][i+1];
+                               return;
+                       }
+               }
+       }
+}
+
+static void
+process_turn_restrictions_dump_coord(struct coord *c, int count)
+{
+       int i;
+       for (i = 0 ; i < count ; i++) {
+               fprintf(stderr,"(0x%x,0x%x)",c[i].x,c[i].y);
+       }
+}
+
+static void
+process_turn_restrictions_finish(GList *tr, FILE *out)
+{
+       GList *l=tr;
+       while (l) {
+               struct turn_restriction *t=l->data;
+               struct coord *c[4];
+               struct item_bin *ib=item_bin;
+
+               if (!t->c_count[0]) {
+                       osm_warning("relation",t->relid,0,"turn restriction: from member not found");
+               } else if (!t->c_count[1]) {
+                       osm_warning("relation",t->relid,0,"turn restriction: via member not found");
+               } else if (!t->c_count[2]) {
+                       osm_warning("relation",t->relid,0,"turn restriction: to member not found");
+               } else {
+                       process_turn_restrictions_fromto(t, 0, c);
+                       process_turn_restrictions_fromto(t, 2, c+2);
+                       if (!c[0] || !c[2]) {
+                               osm_warning("relation",t->relid,0,"turn restriction: via (");
+                               process_turn_restrictions_dump_coord(t->c[1], t->c_count[1]);
+                               fprintf(stderr,")");
+                               if (!c[0]) {
+                                       fprintf(stderr," failed to connect to from (");
+                                       process_turn_restrictions_dump_coord(t->c[0], t->c_count[0]);
+                                       fprintf(stderr,")");
+                               }
+                               if (!c[2]) {
+                                       fprintf(stderr," failed to connect to to (");
+                                       process_turn_restrictions_dump_coord(t->c[2], t->c_count[2]);
+                                       fprintf(stderr,")");
+                               }
+                               fprintf(stderr,"\n");
+                       } else {
+                               if (t->c_count[1] <= 2) {
+                                       item_bin_init(ib,t->type);
+                                       item_bin_add_coord(ib, c[0], 1);
+                                       item_bin_add_coord(ib, c[1], 1);
+                                       if (t->c_count[1] > 1) 
+                                               item_bin_add_coord(ib, c[3], 1);
+                                       item_bin_add_coord(ib, c[2], 1);
+                                       item_bin_write(ib, out);
+                               }
+                               
+                       }
+               }
+               g_free(t);
+               l=g_list_next(l);
+       }
+       g_list_free(tr);
+}
+
+static GList *
+process_turn_restrictions_setup(FILE *in, struct relations *relations)
+{
+       struct relation_member fromm,tom,viam,tmpm;
+       long long relid;
+       struct item_bin *ib;
+       struct relations_func *relations_func;
+       int min_count;
+       GList *turn_restrictions=NULL;
+       
+       fseek(in, 0, SEEK_SET);
+       relations_func=relations_func_new(process_turn_restrictions_member, NULL);
+       while ((ib=read_item(in))) {
+               struct turn_restriction *turn_restriction=g_new0(struct turn_restriction, 1);
+               relid=item_bin_get_relationid(ib);
+               turn_restriction->relid=relid;
+               turn_restriction->type=ib->type;
+               min_count=0;
+               if (!search_relation_member(ib, "from",&fromm,&min_count)) {
+                       osm_warning("relation",relid,0,"turn restriction: from member missing\n");
+                       continue;
+               }
+               if (search_relation_member(ib, "from",&tmpm,&min_count)) {
+                       osm_warning("relation",relid,0,"turn restriction: multiple from members\n");
+                       continue;
+               }
+               min_count=0;
+               if (!search_relation_member(ib, "to",&tom,&min_count)) {
+                       osm_warning("relation",relid,0,"turn restriction: to member missing\n");
+                       continue;
+               }
+               if (search_relation_member(ib, "to",&tmpm,&min_count)) {
+                       osm_warning("relation",relid,0,"turn restriction: multiple to members\n");
+                       continue;
+               }
+               min_count=0;
+               if (!search_relation_member(ib, "via",&viam,&min_count)) {
+                       osm_warning("relation",relid,0,"turn restriction: via member missing\n");
+                       continue;
+               }
+               if (search_relation_member(ib, "via",&tmpm,&min_count)) {
+                       osm_warning("relation",relid,0,"turn restriction: multiple via member\n");
+                       continue;
+               }
+               if (fromm.type != 2) {
+                       osm_warning("relation",relid,0,"turn restriction: wrong type for from member ");
+                       osm_warning(osm_types[fromm.type],fromm.id,1,"\n");
+                       continue;
+               }
+               if (tom.type != 2) {
+                       osm_warning("relation",relid,0,"turn restriction: wrong type for to member ");
+                       osm_warning(osm_types[tom.type],tom.id,1,"\n");
+                       continue;
+               }
+               if (viam.type != 1 && viam.type != 2) {
+                       osm_warning("relation",relid,0,"turn restriction: wrong type for via member ");
+                       osm_warning(osm_types[viam.type],viam.id,1,"\n");
+                       continue;
+               }
+               relations_add_func(relations, relations_func, turn_restriction, (gpointer) 0, fromm.type, fromm.id);
+               relations_add_func(relations, relations_func, turn_restriction, (gpointer) 1, viam.type, viam.id);
+               relations_add_func(relations, relations_func, turn_restriction, (gpointer) 2, tom.type, tom.id);
+               turn_restrictions=g_list_append(turn_restrictions, turn_restriction);
+       }
+       return turn_restrictions;
+}
+
 void
 process_turn_restrictions(FILE *in, FILE *coords, FILE *ways, FILE *ways_index, FILE *out)
 {
@@ -1984,8 +2148,14 @@ process_turn_restrictions(FILE *in, FILE *coords, FILE *ways, FILE *ways_index,
        char from_buffer[65536],to_buffer[65536],via_buffer[65536];
        struct item_bin *ib,*from=(struct item_bin *)from_buffer,*to=(struct item_bin *)to_buffer,*via=(struct item_bin *)via_buffer;
        struct coord *fromc,*toc,*viafrom,*viato,*tmp;
-       fseek(in, 0, SEEK_SET);
        int min_count;
+       fseek(in, 0, SEEK_SET);
+       if (experimental > 1) {
+               struct relations *relations=relations_new();
+               GList *turn_restrictions=process_turn_restrictions_setup(in, relations);
+               relations_process(relations, coords, ways, NULL);
+               process_turn_restrictions_finish(turn_restrictions, out);
+       }
        while ((ib=read_item(in))) {
                relid=item_bin_get_relationid(ib);
                min_count=0;
diff --git a/navit/navit/maptool/osm_relations.c b/navit/navit/maptool/osm_relations.c
new file mode 100644 (file)
index 0000000..d6f63a1
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2011 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "maptool.h"
+#include "attr.h"
+
+struct relations {
+       GHashTable *member_hash[3];
+};
+
+struct relations_func {
+       void (*func)(void *func_priv, void *relation_priv, struct item_bin *member, void *member_priv);
+       void *func_priv;
+};
+
+struct relations_member {
+       osmid memberid;
+       void *relation_priv,*member_priv;
+       struct relations_func *func;
+};
+
+static guint
+relations_member_hash(gconstpointer key)
+{
+       const struct relations_member *memb=key;
+       return (memb->memberid >> 32)^(memb->memberid & 0xffffffff);
+}
+
+static gboolean
+relations_member_equal(gconstpointer a, gconstpointer b)
+{
+       const struct relations_member *memba=a;
+       const struct relations_member *membb=b;
+       return (memba->memberid == membb->memberid);
+}
+
+struct relations *
+relations_new(void)
+{
+       struct relations *ret=g_new(struct relations, 1);
+       int i;
+
+       for (i = 0 ; i < 3 ; i++)
+               ret->member_hash[i]=g_hash_table_new_full(relations_member_hash, relations_member_equal, NULL, NULL);
+       return ret;
+}
+
+struct relations_func *
+relations_func_new(void (*func)(void *func_priv, void *relation_priv, struct item_bin *member, void *member_priv), void *func_priv)
+{
+       struct relations_func *relations_func=g_new(struct relations_func, 1);
+       relations_func->func=func;
+       relations_func->func_priv=func_priv;
+       return relations_func;
+}
+
+void
+relations_add_func(struct relations *rel, struct relations_func *func, void *relation_priv, void *member_priv, int type, osmid id)
+{
+       GHashTable *member_hash=rel->member_hash[type-1];
+       struct relations_member *memb=g_new(struct relations_member, 1);
+       
+       memb->memberid=id;
+       memb->relation_priv=relation_priv;
+       memb->member_priv=member_priv;
+       memb->func=func;
+       g_hash_table_insert(member_hash, memb, g_list_append(g_hash_table_lookup(member_hash, memb), memb));
+}
+
+void
+relations_process(struct relations *rel, FILE *nodes, FILE *ways, FILE *relations)
+{
+       char buffer[128];
+       struct item_bin *ib=(struct item_bin *)buffer;
+       long long *id;
+       struct coord *c=(struct coord *)(ib+1),cn={0,0};
+       struct node_item *ni;
+       GList *l;
+
+       item_bin_init(ib, type_point_unkn);
+       item_bin_add_coord(ib, &cn, 1);
+       item_bin_add_attr_longlong(ib, attr_osm_nodeid, 0);
+       id=item_bin_get_attr(ib, attr_osm_nodeid, NULL);
+       while ((ni=read_node_item(nodes))) {
+               *id=ni->id;
+               *c=ni->c;
+               l=g_hash_table_lookup(rel->member_hash[0], id);
+               while (l) {
+                       struct relations_member *memb=l->data;
+                       memb->func->func(memb->func->func_priv, memb->relation_priv, ib, memb->member_priv);
+                       l=g_list_next(l);
+               }
+       }
+       while ((ib=read_item(ways))) {
+               id=item_bin_get_attr(ib, attr_osm_wayid, NULL);
+               if (id) {
+                       l=g_hash_table_lookup(rel->member_hash[1], id);
+                       while (l) {
+                               struct relations_member *memb=l->data;
+                               memb->func->func(memb->func->func_priv, memb->relation_priv, ib, memb->member_priv);
+                               l=g_list_next(l);
+                       }
+               }
+       }
+}