2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2011 Navit Team
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
33 #include "projection.h"
38 #include "transform.h"
48 csv_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode);
49 static struct item * csv_create_item(struct map_rect_priv *mr, enum item_type it_type);
50 static void quadtree_item_free(void *mr, struct quadtree_item *qitem);
51 static void quadtree_item_free_do(void *qitem);
63 struct quadtree_data *quadtree_data_dup(struct quadtree_data *qdata)
65 struct quadtree_data *ret=g_new0(struct quadtree_data,1);
67 ret->type=qdata->type;
68 ret->id_lo=qdata->id_lo;
69 ret->item=g_new(struct item,1);
70 *(ret->item)=*(qdata->item);
71 for(l=qdata->attr_list;l;l=g_list_next(l)) {
72 ret->attr_list=g_list_prepend(ret->attr_list,attr_dup(l->data));
78 save_map_csv(struct map_priv *m)
80 if(m->filename && m->dirty) {
81 char* filename = g_strdup_printf("%s.tmp",m->filename);
87 struct quadtree_iter *iter;
88 struct quadtree_item *qitem;
90 if( ! (fp=fopen(filename,"w+"))) {
91 dbg(0, "Error opening csv file to write new entries");
95 iter=quadtree_query(m->tree_root, -180, 180, -180, 180, quadtree_item_free, m);
97 while((qitem = quadtree_item_next(iter))!=NULL) {
99 enum attr_type *at = m->attr_types;
104 for(i=0;i<m->attr_cnt;++i) {
105 if(*at == attr_position_latitude) {
106 tmpstr = g_strdup_printf("%lf",qitem->latitude);
107 } else if(*at == attr_position_longitude) {
108 tmpstr = g_strdup_printf("%lf",qitem->longitude);
110 GList* attr_list = ((struct quadtree_data*)(qitem->data))->attr_list;
111 GList* attr_it = attr_list;
112 struct attr* found_attr = NULL;
113 /*search attributes*/
115 if(((struct attr*)(attr_it->data))->type == *at) {
116 found_attr = attr_it->data;
119 attr_it = g_list_next(attr_it);
122 if(ATTR_IS_INT(*at)) {
123 tmpstr = g_strdup_printf("%d", (int)found_attr->u.num);
124 } else if(ATTR_IS_DOUBLE(*at)) {
125 tmpstr = g_strdup_printf("%lf", *found_attr->u.numd);
126 } else if(ATTR_IS_STRING(*at)) {
127 tmpstr = g_strdup(found_attr->u.str);
129 dbg(0,"Cant represent attribute %s\n",attr_to_name(*at));
133 dbg(0,"No value defined for the atribute %s, assuming empty string\n",attr_to_name(*at));
139 csv_line = g_strdup_printf("%s,%s",csv_line,tmpstr);
148 if(fprintf(fp,"%s\n", csv_line)<0) {
159 rename(filename,m->filename);
163 quadtree_query_free(iter);
168 static const int zoom_max = 18;
171 map_destroy_csv(struct map_priv *m)
173 dbg(1,"map_destroy_csv\n");
176 g_hash_table_destroy(m->qitem_hash);
177 quadtree_destroy(m->tree_root);
179 g_free(m->attr_types);
184 csv_coord_rewind(void *priv_data)
189 csv_coord_get(void *priv_data, struct coord *c, int count)
191 struct map_rect_priv *mr=priv_data;
202 csv_attr_rewind(void *priv_data)
204 /*TODO implement if needed*/
208 csv_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
210 int i, bAttrFound = 0;
212 struct map_rect_priv *mr=priv_data;
214 if( !mr || !mr->m || !mr->m->attr_types ) {
218 attr_list = ((struct quadtree_data*)(mr->qitem->data))->attr_list;
220 if (attr_type == attr_any) {
221 if (mr->at_iter==NULL) { /*start iteration*/
222 mr->at_iter = attr_list;
224 *attr = *(struct attr*)(mr->at_iter->data);
226 } else { /*empty attr list*/
230 } else { /*continue iteration*/
231 mr->at_iter = g_list_next(mr->at_iter);
233 *attr = *(struct attr*)mr->at_iter->data;
242 at = mr->m->attr_types;
244 for(i=0;i<mr->m->attr_cnt;++i) {
245 if(*at == attr_type) {
257 if(((struct attr*)attr_list->data)->type == attr_type) {
258 *attr = *(struct attr*)attr_list->data;
261 attr_list = g_list_next(attr_list);
267 csv_attr_set(void *priv_data, struct attr *attr, enum change_mode mode)
269 struct map_rect_priv* mr = (struct map_rect_priv*)priv_data;
270 struct map_priv* m = mr->m;
272 struct attr *attr_new;
273 GList *attr_list, *curr_attr_list;
274 enum attr_type *at = m->attr_types;
276 if(!mr || !mr->qitem) {
280 /*if attribute is not supported by this csv map return 0*/
281 for(i=0;i<m->attr_cnt;++i) {
282 if(*at==attr->type) {
292 attr_new = attr_dup(attr);
293 attr_list = ((struct quadtree_data*)(mr->qitem->data))->attr_list;
294 curr_attr_list = attr_list;
297 if(((struct attr*)attr_list->data)->type == attr->type) {
299 case change_mode_delete:
300 attr_free((struct attr*)attr_list->data);
301 curr_attr_list = g_list_delete_link(curr_attr_list,attr_list);
303 /* FIXME: To preserve consistency, may be the save_map_csv should be called here... */
306 case change_mode_modify:
307 case change_mode_prepend:
308 case change_mode_append:
309 /* replace existing attribute */
310 if(attr_list->data) {
311 attr_free((struct attr*)attr_list->data);
313 attr_list->data = attr_new;
322 attr_list = g_list_next(attr_list);
325 if( mode==change_mode_modify || mode==change_mode_prepend || mode==change_mode_append) {
326 /* add new attribute */
327 curr_attr_list = g_list_prepend(curr_attr_list, attr_new);
328 ((struct quadtree_data*)(mr->qitem->data))->attr_list = curr_attr_list;
338 csv_type_set(void *priv_data, enum item_type type)
340 struct map_rect_priv* mr = (struct map_rect_priv*)priv_data;
341 dbg(1,"Enter %d\n", type);
343 if(!mr || !mr->qitem) {
344 dbg(1,"Nothing to do\n");
351 mr->qitem->deleted=1;
352 dbg(1,"Item %p is deleted\n",mr->qitem);
357 static struct item_methods methods_csv = {
370 * Sets coordinate of an existing item (either on the new list or an item with coord )
373 csv_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode)
375 struct quadtree_item query_item, *insert_item, *query_res;
377 struct map_rect_priv* mr;
379 struct quadtree_item* qi;
381 dbg(1,"Set coordinates %d %d\n", c->x, c->y);
383 /* for now we only support coord modification only */
384 if( ! change_mode_modify) {
387 /* csv driver supports one coord per record only */
392 /* get curr_item of given map_rect */
393 mr = (struct map_rect_priv*)priv_data;
402 transform_to_geo(projection_mg, &c[0], &cg);
404 /* if it is on the new list remove from new list and add it to the tree with the coord */
405 new_it = m->new_items;
407 if(new_it->data==qi) {
410 new_it = g_list_next(new_it);
413 qi->longitude = cg.lng;
414 qi->latitude = cg.lat;
415 quadtree_add( m->tree_root, qi, mr->qiter);
416 dbg(1,"Set coordinates %f %f\n", cg.lng, cg.lat);
417 m->new_items = g_list_remove_link(m->new_items,new_it);
423 /* else update quadtree item with the new coord
424 remove item from the quadtree */
425 query_item.longitude = cg.lng;
426 query_item.latitude = cg.lat;
427 query_res = quadtree_find_item(m->tree_root, &query_item);
431 quadtree_delete_item(m->tree_root, query_res);
432 /* add item to the tree with the new coord */
433 insert_item=g_new0(struct quadtree_item,1);
434 insert_item->data=quadtree_data_dup(query_res->data);
435 insert_item->longitude = cg.lng;
436 insert_item->latitude = cg.lat;
437 quadtree_add(m->tree_root, query_res, mr->qiter);
439 mr->qitem->ref_count--;
440 mr->qitem=insert_item;
441 mr->qitem->ref_count++;
448 static void quadtree_item_free(void *this, struct quadtree_item *qitem)
450 struct map_priv* m=this;
451 struct quadtree_data * qdata=qitem->data;
453 g_hash_table_remove(m->qitem_hash,&(qdata->item->id_lo));
457 static void quadtree_item_free_do(void *data)
459 struct quadtree_item *qitem=data;
462 struct quadtree_data * qdata=qitem->data;
464 for(attr_it = qdata->attr_list;attr_it;attr_it = g_list_next(attr_it)) {
465 attr = attr_it->data;
473 static void map_csv_debug_dump(struct map_priv *map)
475 GList *l=g_hash_table_get_values(map->qitem_hash);
478 struct quadtree_item *qi;
481 dbg(0,"%p del=%d ref=%d\n", qi,qi->deleted, qi->ref_count);
482 attrs=((struct quadtree_data *)qi->data)->attr_list;
484 if(((struct attr*)attrs->data)->type==attr_label)
485 dbg(0,"... %s\n",((struct attr*)attrs->data)->u.str);
486 attrs=g_list_next(attrs);
493 static struct map_rect_priv *
494 map_rect_new_csv(struct map_priv *map, struct map_selection *sel)
496 struct map_rect_priv *mr;
499 struct quadtree_iter *res = NULL;
500 dbg(1,"map_rect_new_csv\n");
503 /* Set above value to 1 to have all map data dumped (including deleted items) to the log at each maprect creation */
504 map_csv_debug_dump(map);
507 mr=g_new0(struct map_rect_priv, 1);
516 mr->item.meth=&methods_csv;
517 mr->item.priv_data=mr;
525 transform_to_geo(projection_mg, &sel->u.c_rect.lu, &lu);
526 transform_to_geo(projection_mg, &sel->u.c_rect.rl, &rl);
528 res=quadtree_query(map->tree_root, lu.lng, rl.lng, rl.lat, lu.lat, quadtree_item_free, mr->m);
535 map_rect_destroy_csv(struct map_rect_priv *mr)
538 mr->qitem->ref_count--;
541 quadtree_query_free(mr->qiter);
547 map_rect_get_item_csv(struct map_rect_priv *mr)
551 mr->qitem->ref_count--;
553 mr->qitem=quadtree_item_next(mr->qiter);
556 struct item* ret=&(mr->item);
558 mr->qitem->ref_count++;
559 mr->item = *(((struct quadtree_data*)(mr->qitem->data))->item);
561 cg.lng = mr->qitem->longitude;
562 cg.lat = mr->qitem->latitude;
563 transform_from_geo(projection_mg, &cg, &mr->c);
570 map_rect_get_item_byid_csv(struct map_rect_priv *mr, int id_hi, int id_lo)
572 /*currently id_hi is ignored*/
574 struct quadtree_item *qit = g_hash_table_lookup(mr->m->qitem_hash,&id_lo);
577 mr->qitem->ref_count--;
581 mr->qitem->ref_count++;
582 mr->item=*(((struct quadtree_data*)(qit->data))->item);
583 mr->item.priv_data=mr;
592 csv_get_attr(struct map_priv *m, enum attr_type type, struct attr *attr)
598 csv_create_item(struct map_rect_priv *mr, enum item_type it_type)
601 struct quadtree_data* qd;
602 struct quadtree_item* qi;
603 struct item* curr_item;
612 if( m->item_type != it_type) {
617 /*add item to the map*/
618 curr_item = item_new("",zoom_max);
619 curr_item->type = m->item_type;
620 curr_item->meth=&methods_csv;
622 curr_item->id_lo = m->next_item_idx;
628 qd = g_new0(struct quadtree_data,1);
629 qi = g_new0(struct quadtree_item,1);
630 qd->item = curr_item;
631 qd->attr_list = NULL;
633 /*we don`t have valid coord yet*/
636 /*add the coord less item to the new list*/
637 m->new_items = g_list_prepend(m->new_items, qi);
639 mr->qitem->ref_count--;
642 mr->item.priv_data=mr;
643 mr->qitem->ref_count++;
644 /*don't add to the quadtree yet, wait until we have a valid coord*/
646 *pID = m->next_item_idx;
647 g_hash_table_insert(m->qitem_hash, pID,qi);
652 static struct map_methods map_methods_csv = {
657 map_rect_destroy_csv,
658 map_rect_get_item_csv,
659 map_rect_get_item_byid_csv,
667 static struct map_priv *
668 map_new_csv(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl)
670 struct map_priv *m = NULL;
671 struct attr *item_type;
672 struct attr *attr_types;
673 struct attr *item_type_attr;
676 struct attr *charset;
680 enum attr_type* attr_type_list = NULL;
681 struct quadtree_node* tree_root = quadtree_node_new(NULL,-180,180,-180,180);
682 m = g_new0(struct map_priv, 1);
684 m->qitem_hash = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, quadtree_item_free_do);
686 item_type = attr_search(attrs, NULL, attr_item_type);
687 attr_types = attr_search(attrs, NULL, attr_attr_types);
689 enum attr_type* at = attr_types->u.attr_types;
690 while(*at != attr_none) {
691 attr_type_list = g_realloc(attr_type_list,sizeof(enum attr_type)*(attr_cnt+1));
692 attr_type_list[attr_cnt] = *at;
693 if(*at==attr_position_latitude) {
696 else if(*at==attr_position_longitude) {
702 m->attr_cnt = attr_cnt;
703 m->attr_types = attr_type_list;
705 m->attr_types = NULL;
709 charset = attr_search(attrs, NULL, attr_charset);
711 dbg(1,"charset:%s\n",charset->u.str);
712 m->charset=g_strdup(charset->u.str);
714 m->charset=g_strdup(map_methods_csv.charset);
717 if(bLonFound==0 || bLatFound==0) {
721 item_type_attr=attr_search(attrs, NULL, attr_item_type);
723 if( !item_type_attr || item_type_attr->u.item_type==type_none) {
727 m->item_type = item_type_attr->u.item_type;
729 data=attr_search(attrs, NULL, attr_data);
732 struct file_wordexp *wexp;
735 wexp=file_wordexp_new(data->u.str);
736 wexp_data=file_wordexp_get_array(wexp);
737 dbg(1,"map_new_csv %s\n", data->u.str);
738 m->filename=g_strdup(wexp_data[0]);
739 file_wordexp_destroy(wexp);
741 /*load csv file into quadtree structure*/
742 /*if column number is wrong skip*/
743 if((fp=fopen(m->filename,"rt"))) {
744 const int max_line_len = 256;
745 char *line=g_alloca(sizeof(char)*max_line_len);
747 if(fgets(line,max_line_len,fp)) {
753 if(line[strlen(line)-1]=='\n' || line[strlen(line)-1]=='\r') {
754 line[strlen(line)-1] = '\0';
756 line2 = g_strdup(line);
757 while((tok=strtok( (col_cnt==0)?line:NULL , delim))) {
761 if(col_cnt==attr_cnt) {
762 int cnt = 0; /*index of current attr*/
764 GList* attr_list = NULL;
766 double longitude = 0.0, latitude=0.0;
767 struct item *curr_item = item_new("",zoom_max);/*does not use parameters*/
768 curr_item->type = item_type_attr->u.item_type;
769 curr_item->id_lo = m->next_item_idx;
774 curr_item->meth=&methods_csv;
777 while((tok=strtok( (cnt==0)?line2:NULL , delim))) {
778 struct attr*curr_attr = g_new0(struct attr,1);
780 curr_attr->type = attr_types->u.attr_types[cnt];
781 if(ATTR_IS_STRING(attr_types->u.attr_types[cnt])) {
782 curr_attr->u.str = g_strdup(tok);
784 else if(ATTR_IS_INT(attr_types->u.attr_types[cnt])) {
785 curr_attr->u.num = atoi(tok);
787 else if(ATTR_IS_DOUBLE(attr_types->u.attr_types[cnt])) {
788 double *d = g_new(double,1);
790 curr_attr->u.numd = d;
791 if(attr_types->u.attr_types[cnt] == attr_position_longitude) {
794 if(attr_types->u.attr_types[cnt] == attr_position_latitude) {
799 /*unknown attribute*/
805 attr_list = g_list_prepend(attr_list, curr_attr);
809 if(bAddSum && (longitude!=0.0 || latitude!=0.0)) {
810 struct quadtree_data* qd = g_new0(struct quadtree_data,1);
811 struct quadtree_item* qi =g_new(struct quadtree_item,1);
812 int* pID = g_new(int,1);
813 qd->item = curr_item;
814 qd->attr_list = attr_list;
816 qi->longitude = longitude;
817 qi->latitude = latitude;
818 quadtree_add(tree_root, qi, NULL);
819 *pID = m->next_item_idx;
820 g_hash_table_insert(m->qitem_hash, pID,qi);
830 dbg(0,"ERROR: Non-matching attr count and column count: %d %d SKIPPING line: %s\n",col_cnt, attr_cnt,line);
838 dbg(0,"Error opening csv map file %d, starting with empty map\n", m->filename);
841 dbg(1,"No data attribute, starting with in-memory map\n");
844 *meth = map_methods_csv;
846 meth->charset=m->charset;
848 m->tree_root = tree_root;
849 dbg(2,"%p\n",tree_root);
850 flags=attr_search(attrs, NULL, attr_flags);
852 m->flags=flags->u.num;
859 dbg(1,"csv: plugin_init\n");
860 plugin_register_map_type("csv", map_new_csv);