/[zanavi_public1]/navit/navit/map/csv/csv.c
ZANavi

Contents of /navit/navit/map/csv/csv.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Mon Feb 4 17:41:59 2013 UTC (6 years, 7 months ago) by zoff99
File MIME type: text/plain
File size: 16857 byte(s)
new map version, lots of fixes and experimental new features
1 /**
2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2011 Navit Team
4 *
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.
8 *
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.
13 *
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.
18 */
19
20 #include <stdlib.h>
21 #include <glib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #include <math.h>
28 #include "config.h"
29 #include "debug.h"
30 #include "plugin.h"
31 #include "projection.h"
32 #include "item.h"
33 #include "map.h"
34 #include "maptype.h"
35 #include "attr.h"
36 #include "transform.h"
37 #include "file.h"
38 #include "quadtree.h"
39
40 #include "csv.h"
41
42 static int map_id;
43
44 //prototype
45 static int
46 csv_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode);
47 static struct item * csv_create_item(struct map_rect_priv *mr, enum item_type it_type);
48
49 struct quadtree_data
50 {
51 struct item* item;
52 GList* attr_list;
53 };
54
55 static void
56 save_map_csv(struct map_priv *m)
57 {
58 if(m->dirty) {
59 GList *res = NULL, *item_it;
60 char* filename = g_strdup_printf("%s.tmp",m->filename);
61 FILE* fp;
62 int ferr = 0;
63 char *csv_line = 0;
64 char *tmpstr = 0;
65 char *oldstr = 0;
66
67 if( ! (fp=fopen(filename,"w+"))) {
68 dbg(1, "Error opening csv file to write new entries");
69 return;
70 }
71 //query the world
72 quadtree_find_rect_items(m->tree_root, -90, 90, -90, 90, &res);
73
74 item_it = res;
75 while(item_it) {
76 int i;
77 enum attr_type *at = m->attr_types;
78 csv_line = g_strdup("");
79 tmpstr = g_strdup("");
80 for(i=0;i<m->attr_cnt;++i) {
81 if(at != m->attr_types) {
82 csv_line = g_strdup_printf("%s,",tmpstr);
83 }
84 g_free(tmpstr);
85 tmpstr = NULL;
86
87 if(*at == attr_position_latitude) {
88 tmpstr = g_strdup_printf("%lf",((struct quadtree_item*)(item_it->data))->latitude);
89 }
90 else if(*at == attr_position_longitude) {
91 tmpstr = g_strdup_printf("%lf",((struct quadtree_item*)(item_it->data))->longitude);
92 }
93 else {
94 GList* attr_list = ((struct quadtree_data*)(((struct quadtree_item*)(item_it->data))->data))->attr_list;
95 GList* attr_it = attr_list;
96 struct attr* found_attr = NULL;
97 //search attributes
98 while(attr_it) {
99 if(((struct attr*)(attr_it->data))->type == *at) {
100 found_attr = attr_it->data;
101 break;
102 }
103 attr_it = g_list_next(attr_it);
104 }
105 if(found_attr) {
106 if(ATTR_IS_INT(*at)) {
107 tmpstr = g_strdup_printf("%d", found_attr->u.num);
108 }
109 else if(ATTR_IS_DOUBLE(*at)) {
110 tmpstr = g_strdup_printf("%lf", *found_attr->u.numd);
111 }
112 else if(ATTR_IS_STRING(*at)) {
113 tmpstr = g_strdup(found_attr->u.str);
114 }
115 }
116 else { //TODO handle this error
117 }
118 }
119 oldstr = csv_line;
120 csv_line = g_strdup_printf("%s%s",csv_line,tmpstr);
121 g_free(tmpstr);
122 g_free(oldstr);
123 tmpstr = csv_line;
124 ++at;
125 }
126 if(fprintf(fp,"%s\n", csv_line)<0) {
127 ferr = 1;
128 }
129 item_it = g_list_next(item_it);
130 tmpstr=g_strdup("");
131 }
132
133 if(fclose(fp)) {
134 ferr = 1;
135 }
136
137 if(! ferr) {
138 unlink(m->filename);
139 rename(filename,m->filename);
140 }
141 g_free(filename);
142 m->dirty = 0;
143 }
144 }
145
146 static const int zoom_max = 18;
147
148 static void
149 map_destroy_csv(struct map_priv *m)
150 {
151 dbg(1,"map_destroy_csv\n");
152 //save if changed
153 save_map_csv(m);
154 g_hash_table_destroy(m->item_hash);
155 g_hash_table_destroy(m->qitem_hash);
156 quadtree_destroy(m->tree_root);
157 g_free(m->filename);
158 g_free(m->attr_types);
159 g_free(m);
160 }
161
162 static void
163 csv_coord_rewind(void *priv_data)
164 {
165 }
166
167 static int
168 csv_coord_get(void *priv_data, struct coord *c, int count)
169 {
170 struct map_rect_priv *mr=priv_data;
171 if(mr) {
172 *c = mr->c;
173 return 1;
174 }
175 else {
176 return 0;
177 }
178 }
179
180 static void
181 csv_attr_rewind(void *priv_data)
182 {
183 // struct map_rect_priv *mr=priv_data;
184 //TODO implement if needed
185 }
186
187 static int
188 csv_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
189 {
190 int i, bAttrFound = 0;
191 GList* attr_list;
192 struct map_rect_priv *mr=priv_data;
193 enum attr_type *at = mr->m->attr_types;
194
195 for(i=0;i<mr->m->attr_cnt;++i) {
196 if(*at == attr_type) {
197 bAttrFound = 1;
198 break;
199 }
200 ++at;
201 }
202
203 if(!bAttrFound) {
204 return 0;
205 }
206
207 if(!mr || !mr->curr_item || !mr->curr_item->data ) {
208 return 0;
209 }
210
211 attr_list = ((struct quadtree_data*)(((struct quadtree_item*)(mr->curr_item->data))->data))->attr_list;
212
213 while(attr_list) {
214 if(((struct attr*)attr_list->data)->type == attr_type) {
215 *attr = *(struct attr*)attr_list->data;
216 return 1;
217 }
218 attr_list = g_list_next(attr_list);
219 }
220 return 0;
221 }
222
223 static int
224 csv_attr_set(void *priv_data, struct attr *attr, enum change_mode mode)
225 {
226 struct map_rect_priv* mr = (struct map_rect_priv*)priv_data;
227 struct map_priv* m = mr->m;
228 int i, bFound = 0;
229 struct attr *attr_new;
230 GList *attr_list, *curr_attr_list;
231 enum attr_type *at = m->attr_types;
232
233 if(!mr || !mr->curr_item || !mr->curr_item->data ) {
234 return 0;
235 }
236
237 //if attribute is not supported by this csv map return 0
238 for(i=0;i<m->attr_cnt;++i) {
239 if(*at==attr->type) {
240 bFound = 1;
241 break;
242 }
243 ++at;
244 }
245 if( ! bFound) {
246 return 0;
247 }
248 m->dirty = 1;
249 attr_new = attr_dup(attr);
250 attr_list = ((struct quadtree_data*)(((struct quadtree_item*)(mr->curr_item->data))->data))->attr_list;
251 curr_attr_list = attr_list;
252
253 while(attr_list) {
254 if(((struct attr*)attr_list->data)->type == attr->type) {
255 switch(mode) {
256 case change_mode_delete:
257 curr_attr_list = g_list_delete_link(curr_attr_list,attr_list->data);
258 return 1;
259 case change_mode_modify:
260 case change_mode_prepend:
261 case change_mode_append:
262 //replace existing attribute
263 if((struct attr*)attr_list->data) {
264 g_free((struct attr*)attr_list->data);
265 }
266 attr_list->data = attr_new;
267 m->dirty = 1;
268 save_map_csv(m);
269 return 1;
270 default:
271 g_free(attr_new);
272 return 0;
273 }
274 }
275 attr_list = g_list_next(attr_list);
276 }
277
278 if( mode==change_mode_modify || mode==change_mode_prepend || mode==change_mode_append) {
279 //add new attribute
280 curr_attr_list = g_list_prepend(curr_attr_list, attr_new);
281 ((struct quadtree_data*)(((struct quadtree_item*)(mr->curr_item->data))->data))->attr_list = curr_attr_list;
282 m->dirty = 1;
283 save_map_csv(m);
284 return 1;
285 }
286 g_free(attr_new);
287 return 0;
288 }
289
290 static struct item_methods methods_csv = {
291 csv_coord_rewind,
292 csv_coord_get,
293 csv_attr_rewind,
294 csv_attr_get,
295 NULL,
296 csv_attr_set,
297 csv_coord_set,
298 };
299
300
301 /*
302 * Sets coordinate of an existing item (either on the new list or an item with coord )
303 */
304 static int
305 csv_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode)
306 {
307 struct quadtree_item query_item, insert_item, *query_res;
308 struct coord_geo cg;
309 struct map_rect_priv* mr;
310 struct map_priv* m;
311 struct quadtree_item* qi;
312 GList* new_it;
313
314 //for now we only support coord modification only
315 if( ! change_mode_modify) {
316 return 0;
317 }
318 //csv driver supports one coord per record only
319 if( count != 1) {
320 return 0;
321 }
322
323 //get curr_item of given map_rect
324 mr = (struct map_rect_priv*)priv_data;
325 m = mr->m;
326
327 if(!mr->curr_item || !mr->curr_item->data) {
328 return 0;
329 }
330
331 qi = mr->curr_item->data;
332
333 transform_to_geo(projection_mg, &c[0], &cg);
334
335 //if it is on the new list remove from new list and add it to the tree with the coord
336 new_it = m->new_items;
337 while(new_it) {
338 if(new_it->data==qi) {
339 break;
340 }
341 new_it = g_list_next(new_it);
342 }
343 if(new_it) {
344 qi->longitude = cg.lng;
345 qi->latitude = cg.lat;
346 quadtree_add( m->tree_root, qi);
347 m->new_items = g_list_remove_link(m->new_items,new_it);
348 return 0;
349 }
350
351 //else update quadtree item with the new coord
352 // remove item from the quadtree (to be implemented)
353 query_item.longitude = cg.lng;
354 query_item.latitude = cg.lat;
355 query_res = quadtree_find_item(m->tree_root, &query_item);
356 if(!query_res) {
357 return 0;
358 }
359 // add item to the tree with the new coord
360 insert_item = *query_res;
361 insert_item.longitude = cg.lng;
362 insert_item.latitude = cg.lat;
363 quadtree_delete_item(m->tree_root, query_res);
364 g_free(query_res);
365 quadtree_add( m->tree_root, &insert_item);
366 m->dirty = 1;
367 save_map_csv(m);
368 return 1;
369 }
370
371 static struct map_rect_priv *
372 map_rect_new_csv(struct map_priv *map, struct map_selection *sel)
373 {
374 struct map_rect_priv *mr;
375 struct coord_geo lu;
376 struct coord_geo rl;
377 GList*res = NULL;
378
379 dbg(1,"map_rect_new_csv\n");
380 mr=g_new0(struct map_rect_priv, 1);
381 mr->m=map;
382 mr->bStarted = 0;
383 mr->sel=sel;
384 if (map->flags & 1)
385 mr->item.id_hi=1;
386 else
387 mr->item.id_hi=0;
388 mr->item.id_lo=0;
389 mr->item.meth=&methods_csv;
390 mr->item.priv_data=mr;
391
392 //convert selection to geo
393 if(sel) {
394 transform_to_geo(projection_mg, &sel->u.c_rect.lu, &lu);
395 transform_to_geo(projection_mg, &sel->u.c_rect.rl, &rl);
396 quadtree_find_rect_items(map->tree_root, lu.lng, rl.lng, rl.lat, lu.lat, &res);
397 }
398 mr->query_result = res;
399 mr->curr_item = res;
400 return mr;
401 }
402
403
404 static void
405 map_rect_destroy_csv(struct map_rect_priv *mr)
406 {
407 g_list_free(mr->query_result);
408 g_free(mr);
409 }
410
411 static struct item *
412 map_rect_get_item_csv(struct map_rect_priv *mr)
413 {
414 if(mr->bStarted) {
415 if(mr->curr_item) {
416 mr->curr_item = g_list_next(mr->curr_item);
417 }
418 }
419 else {
420 mr->bStarted = 1;
421 }
422
423 if(mr->curr_item) {
424 struct item* ret;
425 struct coord_geo cg;
426 ret = ((struct quadtree_data*)(((struct quadtree_item*)(mr->curr_item->data))->data))->item;
427 ret->priv_data=mr;
428 if(mr->curr_item && mr->curr_item->data) {
429 cg.lng = ((struct quadtree_item*)(mr->curr_item->data))->longitude;
430 cg.lat = ((struct quadtree_item*)(mr->curr_item->data))->latitude;
431 transform_from_geo(projection_mg, &cg, &mr->c);
432 ret = ((struct quadtree_data*)(((struct quadtree_item*)(mr->curr_item->data))->data))->item;
433 return ret;
434 }
435 }
436 return NULL;
437 }
438
439 static struct item *
440 map_rect_get_item_byid_csv(struct map_rect_priv *mr, int id_hi, int id_lo)
441 {
442 //currently id_hi is ignored
443 struct item *it = g_hash_table_lookup(mr->m->item_hash,&id_lo);
444 struct quadtree_item *qit = g_hash_table_lookup(mr->m->qitem_hash,&id_lo);
445 if(it && qit) {
446 mr->curr_item = g_list_prepend(NULL, qit);
447 }
448 else {
449 mr->curr_item = NULL;
450 }
451 return it;
452 }
453
454 static int
455 csv_get_attr(struct map_priv *m, enum attr_type type, struct attr *attr)
456 {
457 return 0;
458 }
459
460 static struct item *
461 csv_create_item(struct map_rect_priv *mr, enum item_type it_type)
462 {
463 struct map_priv* m;
464 struct quadtree_data* qd;
465 struct quadtree_item* qi;
466 struct item* curr_item;
467 int* pID;
468 if(mr && mr->m) {
469 m = mr->m;
470 }
471 else {
472 return NULL;
473 }
474
475 if( m->item_type != it_type) {
476 return NULL;
477 }
478
479 m->dirty = 1;
480 //add item to the map
481 curr_item = item_new("",zoom_max);
482 curr_item->type = m->item_type;
483 curr_item->priv_data = mr;
484
485 curr_item->id_lo = m->next_item_idx;
486 if (m->flags & 1)
487 curr_item->id_hi=1;
488 else
489 curr_item->id_hi=0;
490 curr_item->meth=&methods_csv;
491
492 qd = g_new0(struct quadtree_data,1);
493 qi = g_new0(struct quadtree_item,1);
494 qd->item = curr_item;
495 qd->attr_list = NULL;
496 qi->data = qd;
497 //we don`t have valid coord yet
498 qi->longitude = 0;
499 qi->latitude = 0;
500 //add the coord less item to the new list
501 //TODO remove unnecessary indirection
502 m->new_items = g_list_prepend(m->new_items, qi);
503 mr->curr_item = m->new_items;
504 //don't add to the quadtree yet, wait until we have a valid coord
505 pID = g_new(int,1);
506 *pID = m->next_item_idx;
507 g_hash_table_insert(m->item_hash, pID,curr_item);
508 g_hash_table_insert(m->qitem_hash, pID,qi);
509 ++m->next_item_idx;
510 return curr_item;
511 }
512
513 static struct map_methods map_methods_csv = {
514 projection_mg,
515 "iso8859-1",
516 map_destroy_csv,
517 map_rect_new_csv,
518 map_rect_destroy_csv,
519 map_rect_get_item_csv,
520 map_rect_get_item_byid_csv,
521 NULL,
522 NULL,
523 NULL,
524 csv_create_item,
525 csv_get_attr,
526 };
527
528 static struct map_priv *
529 map_new_csv(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl)
530 {
531 struct map_priv *m = NULL;
532 struct attr *item_type;
533 struct attr *attr_types;
534 struct attr *item_type_attr;
535 struct attr *data;
536 struct attr *flags;
537 int bLonFound = 0;
538 int bLatFound = 0;
539 int attr_cnt = 0;
540 enum attr_type* attr_type_list = NULL;
541 struct quadtree_node* tree_root = quadtree_node_new(NULL,-90,90,-90,90);
542 m = g_new0(struct map_priv, 1);
543 m->id = ++map_id;
544 m->qitem_hash = g_hash_table_new(g_int_hash, g_int_equal);
545 m->item_hash = g_hash_table_new_full(g_int_hash, g_int_equal,g_free_func,g_free_func);
546
547 item_type = attr_search(attrs, NULL, attr_item_type);
548 attr_types = attr_search(attrs, NULL, attr_attr_types);
549 if(attr_types) {
550 enum attr_type* at = attr_types->u.attr_types;
551 while(*at != attr_none) {
552 attr_type_list = g_realloc(attr_type_list,sizeof(enum attr_type)*(attr_cnt+1));
553 attr_type_list[attr_cnt] = *at;
554 if(*at==attr_position_latitude) {
555 bLatFound = 1;
556 }
557 else if(*at==attr_position_longitude) {
558 bLonFound = 1;
559 }
560 ++attr_cnt;
561 ++at;
562 }
563 m->attr_cnt = attr_cnt;
564 m->attr_types = attr_type_list;
565 }
566 else {
567 return NULL;
568 }
569
570 if(bLonFound==0 || bLatFound==0) {
571 return NULL;
572 }
573
574 item_type_attr=attr_search(attrs, NULL, attr_item_type);
575
576 if( !item_type_attr || item_type_attr->u.item_type==type_none) {
577 return NULL;
578 }
579
580 m->item_type = item_type_attr->u.item_type;
581
582 data=attr_search(attrs, NULL, attr_data);
583
584 if(data) {
585 //load csv file into quadtree structure
586 //if column number is wrong skip
587 FILE*fp;
588 if((fp=fopen(data->u.str,"rt"))) {
589 const int max_line_len = 256;
590 char *line=g_alloca(sizeof(char)*max_line_len);
591 while(!feof(fp)) {
592 if(fgets(line,max_line_len,fp)) {
593 char*line2;
594 char* delim = ",";
595 int col_cnt=0;
596 char*tok;
597
598 if(line[strlen(line)-1]=='\n' || line[strlen(line)-1]=='\r') {
599 line[strlen(line)-1] = '\0';
600 }
601 line2 = g_strdup(line);
602 while((tok=strtok( (col_cnt==0)?line:NULL , delim))) {
603 ++col_cnt;
604 }
605
606 if(col_cnt==attr_cnt) {
607 int cnt = 0; //idx of current attr
608 char*tok;
609 GList* attr_list = NULL;
610 int bAddSum = 1;
611 double longitude = 0.0, latitude=0.0;
612 struct item *curr_item = item_new("",zoom_max);//does not use parameters
613 curr_item->type = item_type_attr->u.item_type;
614 curr_item->id_lo = m->next_item_idx;
615 if (m->flags & 1)
616 curr_item->id_hi=1;
617 else
618 curr_item->id_hi=0;
619 curr_item->meth=&methods_csv;
620
621
622 while((tok=strtok( (cnt==0)?line2:NULL , delim))) {
623 struct attr*curr_attr = g_new0(struct attr,1);
624 int bAdd = 1;
625 curr_attr->type = attr_types->u.attr_types[cnt];
626 if(ATTR_IS_STRING(attr_types->u.attr_types[cnt])) {
627 curr_attr->u.str = g_strdup(tok);
628 }
629 else if(ATTR_IS_INT(attr_types->u.attr_types[cnt])) {
630 curr_attr->u.num = atoi(tok);
631 }
632 else if(ATTR_IS_DOUBLE(attr_types->u.attr_types[cnt])) {
633 double *d = g_new(double,1);
634 *d = atof(tok);
635 curr_attr->u.numd = d;
636 if(attr_types->u.attr_types[cnt] == attr_position_longitude) {
637 longitude = *d;
638 }
639 if(attr_types->u.attr_types[cnt] == attr_position_latitude) {
640 latitude = *d;
641 }
642 }
643 else {
644 //unknown attribute
645 bAddSum = bAdd = 0;
646 g_free(curr_attr);
647 }
648
649 if(bAdd) {
650 attr_list = g_list_prepend(attr_list, curr_attr);
651 }
652 ++cnt;
653 }
654 if(bAddSum && (longitude!=0.0 || latitude!=0.0)) {
655 struct quadtree_data* qd = g_new0(struct quadtree_data,1);
656 struct quadtree_item* qi =g_new(struct quadtree_item,1);
657 int* pID = g_new(int,1);
658 qd->item = curr_item;
659 qd->attr_list = attr_list;
660 qi->data = qd;
661 qi->longitude = longitude;
662 qi->latitude = latitude;
663 quadtree_add(tree_root, qi);
664 *pID = m->next_item_idx;
665 g_hash_table_insert(m->item_hash, pID,curr_item);
666 g_hash_table_insert(m->qitem_hash, pID,qi);
667 ++m->next_item_idx;
668 }
669 else {
670 g_free(curr_item);
671 }
672
673 }
674 else {
675 //printf("ERROR: Non-matching attr count and column count: %d %d SKIPPING line: %s\n",col_cnt, attr_cnt,line);
676 }
677 g_free(line2);
678 }
679 }
680 fclose(fp);
681 m->filename = g_strdup(data->u.str);
682 }
683 else {
684 return NULL;
685 }
686 }
687
688 *meth = map_methods_csv;
689 m->tree_root = tree_root;
690 flags=attr_search(attrs, NULL, attr_flags);
691 if (flags)
692 m->flags=flags->u.num;
693 return m;
694 }
695
696 void
697 plugin_init(void)
698 {
699 dbg(1,"csv: plugin_init\n");
700 plugin_register_map_type("csv", map_new_csv);
701 }
702

   
Visit the ZANavi Wiki