Contents of /trunk/src/map_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations)
Tue Dec 16 17:00:20 2008 UTC (15 years, 5 months ago) by harbaum
File MIME type: text/plain
File size: 29385 byte(s)
initial line mod support and some small fixes
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of OSM2Go.
5     *
6     * OSM2Go is free software: you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * OSM2Go is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include "appdata.h"
21    
22     /* --------------------- misc local helper functions ---------------- */
23    
24     static void transfer_relations(osm_t *osm, way_t *dst, way_t *src) {
25    
26     /* transfer relation memberships from the src way to the dst one */
27     relation_chain_t *rchain = osm_way_to_relation(osm, src);
28    
29     while(rchain) {
30     relation_chain_t *next = rchain->next;
31     printf("way #%ld is part of relation #%ld\n", src->id,
32     rchain->relation->id);
33    
34     /* make new member of the same relation */
35    
36     /* walk member chain. save role of way if its being found. */
37     member_t **member = &rchain->relation->member;
38     char *role = NULL;
39     while(*member) {
40     /* save role of way */
41     if(((*member)->type == WAY) && ((*member)->way == src))
42     role = (*member)->role;
43     member = &(*member)->next;
44     }
45    
46     printf(" adding way #%ld to relation\n", dst->id);
47     *member = g_new0(member_t, 1);
48     (*member)->type = WAY;
49     (*member)->way = dst;
50     if(role) (*member)->role = g_strdup(role);
51     member = &(*member)->next;
52    
53     rchain->relation->flags |= OSM_FLAG_DIRTY;
54    
55     g_free(rchain);
56     rchain = next;
57     }
58     }
59    
60    
61     /* combine tags from src to dst and combine them in a useful manner */
62     /* erase all source tags */
63     static gboolean combine_tags(tag_t **dst, tag_t *src) {
64     gboolean conflict = FALSE;
65     tag_t *dst_orig = *dst;
66    
67     /* ---------- transfer tags from way[1] to way[0] ----------- */
68     while(*dst) dst = &((*dst)->next); /* find end of target tag list */
69     while(src) {
70     /* check if same key but with different value is present, */
71     /* ignoring the created_by tags */
72     if(!osm_is_creator_tag(src) &&
73     osm_tag_key_other_value_present(dst_orig, src))
74     conflict = TRUE;
75    
76     /* don't copy "created_by" and "source" tag or tags that already */
77     /* exist in identical form */
78     if(osm_is_creator_tag(src) ||
79     osm_tag_key_and_value_present(dst_orig, src)) {
80     tag_t *next = src->next;
81     osm_tag_free(src);
82     src = next;
83     } else {
84     *dst = src;
85     src = src->next;
86     dst = &((*dst)->next);
87     *dst = NULL;
88     }
89     }
90     return conflict;
91     }
92    
93     /* -------------------------- way_add ----------------------- */
94    
95     void map_edit_way_add_begin(map_t *map, way_t *way_sel) {
96     if(way_sel) printf("previously selected way is #%ld\n", way_sel->id);
97    
98     g_assert(!map->action.way);
99     map->action.way = osm_way_new();
100     map->action.extending = NULL;
101     }
102    
103     void map_edit_way_add_segment(map_t *map, gint x, gint y) {
104    
105     /* convert mouse position to canvas (world) position */
106     canvas_window2world(map->canvas, x, y, &x, &y);
107    
108     /* check if this was a double click. This is the case if */
109     /* the last node placed is less than 5 pixels from the current */
110     /* position */
111     node_t *lnode = osm_way_get_last_node(map->action.way);
112     if(lnode && (map->state->zoom * sqrt((lnode->lpos.x-x)*(lnode->lpos.x-x)+
113     (lnode->lpos.y-y)*(lnode->lpos.y-y))) < 5) {
114     #if 0
115     printf("detected double click -> simulate ok click\n");
116     map_hl_touchnode_clear(map);
117     map_action_ok(map->appdata);
118     #else
119     printf("detected double click -> ignore it as accidential\n");
120     #endif
121     } else {
122    
123     /* use the existing node if one was touched */
124     node_t *node = map_hl_touchnode_get_node(map);
125     if(node) {
126     printf(" re-using node #%ld\n", node->id);
127     map_hl_touchnode_clear(map);
128    
129     g_assert(map->action.way);
130    
131     /* check whether this node is first or last one of a different way */
132     way_t *touch_way = NULL;
133     way_chain_t *way_chain = osm_node_to_way(map->appdata->osm, node);
134     while(way_chain) {
135     way_chain_t *next = way_chain->next;
136    
137     if(node == osm_way_get_last_node(way_chain->way)) {
138     printf(" way #%ld ends with this node\n", way_chain->way->id);
139     if(!touch_way) touch_way = way_chain->way;
140     }
141    
142     if(node == osm_way_get_first_node(way_chain->way)) {
143     printf(" way #%ld starts with this node\n", way_chain->way->id);
144     if(!touch_way) touch_way = way_chain->way;
145     }
146    
147     g_free(way_chain);
148     way_chain = next;
149     }
150    
151     /* remeber this way as this may be the last node placed */
152     /* and we might want to join this with this other way */
153     map->action.ends_on = touch_way;
154    
155     /* is this the first node the user places? */
156     if(!map->action.way->node_chain) {
157     map->action.extending = touch_way;
158    
159     if(map->action.extending) {
160     if(!yes_no_f(GTK_WIDGET(map->appdata->window),
161     map->appdata, MISC_AGAIN_ID_EXTEND_WAY, 0,
162     _("Extend way?"),
163     _("Do you want to extend the way present at this location?")))
164     map->action.extending = NULL;
165     else
166     /* there are immediately enough nodes for a valid way */
167     icon_bar_map_cancel_ok(map->appdata, TRUE, TRUE);
168     }
169     }
170    
171     } else {
172     /* the current way doesn't end on another way if we are just placing */
173     /* a new node */
174     map->action.ends_on = NULL;
175    
176     if(!osm_position_within_bounds(map->appdata->osm, x, y))
177     map_outside_error(map->appdata);
178     else
179     node = osm_node_new(map->appdata->osm, x, y);
180     }
181    
182     if(node) {
183     g_assert(map->action.way);
184     osm_way_append_node(map->action.way, node);
185    
186     switch(osm_node_chain_length(map->action.way->node_chain)) {
187     case 1:
188     /* replace "place first node..." message */
189     statusbar_set(map->appdata, _("Place next node of way"), FALSE);
190     break;
191    
192     case 2:
193     /* two nodes are enough for a valid way */
194     icon_bar_map_cancel_ok(map->appdata, TRUE, TRUE);
195     break;
196    
197     default:
198     break;
199     }
200    
201     /* remove prior version of this way */
202     map_item_chain_destroy(&map->action.way->map_item_chain);
203    
204     /* draw current way */
205     josm_elemstyles_colorize_way(map->style, map->action.way);
206     map_way_draw(map, map->action.way);
207     }
208     }
209     }
210    
211     void map_edit_way_add_cancel(map_t *map) {
212    
213     printf(" removing temporary way\n");
214     g_assert(map->action.way);
215    
216     /* remove all nodes that have been created for this way */
217     /* (their way count will be 0 after removing the way) */
218     node_chain_t *chain = map->action.way->node_chain;
219     while(chain) {
220     node_chain_t *next = chain->next;
221    
222     printf(" node #%ld (used by %d)\n",
223     chain->node->id, chain->node->ways);
224    
225     chain->node->ways--;
226     if(!chain->node->ways && (chain->node->id == ID_ILLEGAL)) {
227     printf(" -> freeing temp node\n");
228     osm_node_free(&map->appdata->icon, chain->node);
229     }
230     g_free(chain);
231     chain = next;
232     }
233     map->action.way->node_chain = NULL;
234    
235     /* remove ways visual representation */
236     map_item_chain_destroy(&map->action.way->map_item_chain);
237    
238     osm_way_free(map->action.way);
239     map->action.way = NULL;
240     }
241    
242     void map_edit_way_add_ok(map_t *map) {
243     g_assert(map->action.way);
244    
245     /* transfer all nodes that have been created for this way */
246     /* into the node chain */
247    
248     /* (their way count will be 0 after removing the way) */
249     node_chain_t *chain = map->action.way->node_chain;
250     while(chain) {
251     printf(" node #%ld (used by %d)\n",
252     chain->node->id, chain->node->ways);
253    
254     /* a node may have been a stand-alone node before, so remove its */
255     /* visual representation as its now drawn as part of the way */
256     /* (if at all) */
257     if(chain->node->id != ID_ILLEGAL)
258     map_item_chain_destroy(&chain->node->map_item_chain);
259    
260     map_node_draw(map, chain->node);
261    
262     /* we can be sure that no node gets inserted twice (even if twice in */
263     /* the ways chain) because it gets assigned a non-ID_ILLEGAL id when */
264     /* being moved to the osm node chain */
265     if(chain->node->id == ID_ILLEGAL)
266     osm_node_attach(map->appdata->osm, chain->node);
267    
268     chain = chain->next;
269     }
270    
271     /* attach to existing way if the user requested so */
272     gboolean revert = FALSE;
273     if(map->action.extending) {
274     node_t *nfirst = map->action.way->node_chain->node;
275    
276     printf(" request to extend way #%ld\n", map->action.extending->id);
277    
278     if(osm_way_get_first_node(map->action.extending) == nfirst) {
279     printf(" need to prepend\n");
280     osm_way_revert(map->action.extending);
281     revert = TRUE;
282     } else if(osm_way_get_last_node(map->action.extending) == nfirst)
283     printf(" need to append\n");
284    
285     /* search end of way to be extended */
286     node_chain_t *chain = map->action.extending->node_chain;
287     g_assert(chain);
288     while(chain->next) chain = chain->next;
289    
290     /* skip first node of new way as its the same as the last one of the */
291     /* way we are attaching it to */
292     chain->next = map->action.way->node_chain->next;
293    
294     /* terminate new way afer first node */
295     map->action.way->node_chain->next = NULL;
296    
297     /* erase and free new way (now only containing the first node anymore) */
298     map_item_chain_destroy(&map->action.way->map_item_chain);
299     osm_way_free(map->action.way);
300    
301     map->action.way = map->action.extending;
302     map->action.way->flags |= OSM_FLAG_DIRTY;
303    
304     /* and undo reversion of required */
305     if(revert)
306     osm_way_revert(map->action.way);
307    
308     } else {
309     /* now move the way itself into the main data structure */
310     osm_way_attach(map->appdata->osm, map->action.way);
311     }
312    
313     /* we might already be working on the "ends_on" way as we may */
314     /* be extending it. Joining the same way doesn't make sense. */
315     if(map->action.ends_on && (map->action.ends_on == map->action.way)) {
316     printf(" the new way ends on itself -> don't join itself\n");
317     map->action.ends_on = NULL;
318     }
319    
320     if(map->action.ends_on)
321     if(!yes_no_f(GTK_WIDGET(map->appdata->window),
322     map->appdata, MISC_AGAIN_ID_EXTEND_WAY_END, 0,
323     _("Join way?"),
324     _("Do you want to join the way present at this location?")))
325     map->action.ends_on = NULL;
326    
327     if(map->action.ends_on) {
328     printf(" this new way ends on another way\n");
329    
330     /* if revert is true the node in question is the first one */
331     /* of the newly created way. thus is it revertes again before */
332     /* attaching and the result is finally reverted once more */
333    
334     /* this is slightly more complex as this time two full tagged */
335     /* ways may be involved as the new way may be an extended existing */
336     /* way being connected to another way. This happens if you connect */
337     /* two existing ways using a new way between them */
338    
339     if(revert) osm_way_revert(map->action.way);
340    
341     /* and open dialog to resolve tag collisions if necessary */
342     if(combine_tags(&map->action.way->tag, map->action.ends_on->tag))
343     messagef(GTK_WIDGET(map->appdata->window), _("Way tag conflict"),
344     _("The resulting way contains some conflicting tags. "
345     "Please solve these."));
346    
347     map->action.ends_on->tag = NULL;
348    
349     /* make way member of all relations ends_on already is */
350     transfer_relations(map->appdata->osm, map->action.way, map->action.ends_on);
351    
352     /* check if we have to revert (again?) to match the way order */
353     if(osm_way_get_last_node(map->action.ends_on) ==
354     osm_way_get_last_node(map->action.way)) {
355    
356     printf(" need to prepend ends_on\n");
357    
358     /* need to revert ends_on way */
359     osm_way_revert(map->action.ends_on);
360     revert = !revert;
361     }
362    
363     /* search end of node chain */
364     node_chain_t *chain = map->action.way->node_chain;
365     g_assert(chain);
366     while(chain->next) chain = chain->next;
367    
368     /* attach ends_on way to way but omit first node */
369     chain->next = map->action.ends_on->node_chain->next;
370     map->action.ends_on->node_chain->next = NULL;
371    
372     /* erase and free ends_on (now only containing the first node anymore) */
373     map_way_delete(map->appdata, map->action.ends_on);
374    
375     if(revert) osm_way_revert(map->action.way);
376     }
377    
378     /* remove prior version of this way */
379     map_item_chain_destroy(&map->action.way->map_item_chain);
380    
381     /* draw the updated way */
382     map_way_draw(map, map->action.way);
383    
384     map_way_select(map->appdata, map->action.way);
385    
386     map->action.way = NULL;
387    
388     /* let the user specify some tags for the new way */
389     info_dialog(GTK_WIDGET(map->appdata->window), map->appdata, NULL);
390     }
391    
392     /* -------------------------- way_node_add ----------------------- */
393    
394     void map_edit_way_node_add_highlight(map_t *map, map_item_t *item,
395     gint x, gint y) {
396     if(map_item_is_selected_way(map, item)) {
397     gint nx, ny;
398     canvas_window2world(map->canvas, x, y, &nx, &ny);
399 harbaum 15 if(canvas_item_get_segment(item->item, nx, ny) >= 0)
400 harbaum 1 map_hl_cursor_draw(map, x, y, FALSE, map->style->node.radius);
401     }
402     }
403    
404     void map_edit_way_node_add(map_t *map, gint x, gint y) {
405     /* check if we are still hovering above the selected way */
406 harbaum 15 map_item_t *item = map_real_item_at(map, x, y);
407 harbaum 1 if(item && map_item_is_selected_way(map, item)) {
408     /* convert mouse position to canvas (world) position */
409     canvas_window2world(map->canvas, x, y, &x, &y);
410     gint insert_after = canvas_item_get_segment(item->item, x, y)+1;
411     if(insert_after > 0) {
412     /* create new node */
413     node_t* node = osm_node_new(map->appdata->osm, x, y);
414     osm_node_attach(map->appdata->osm, node);
415    
416     /* insert it into ways chain of nodes */
417     way_t *way = item->way;
418    
419     /* search correct position */
420     node_chain_t **chain = &way->node_chain;
421     while(insert_after--) {
422     g_assert(*chain);
423     chain = &(*chain)->next;
424     }
425    
426     /* and actually do the insertion */
427     node_chain_t *new_chain_item = g_new0(node_chain_t, 1);
428     new_chain_item->node = node;
429     new_chain_item->next = *chain;
430     *chain = new_chain_item;
431    
432     /* clear selection */
433     map_item_deselect(map->appdata);
434    
435     /* remove prior version of this way */
436     map_item_chain_destroy(&way->map_item_chain);
437    
438     /* draw the updated way */
439     map_way_draw(map, way);
440    
441     /* remember that this node is contained in one way */
442     node->ways=1;
443    
444     /* and that the way needs to be uploaded */
445     way->flags |= OSM_FLAG_DIRTY;
446    
447     /* put gui into idle state */
448     map_action_set(map->appdata, MAP_ACTION_IDLE);
449    
450     /* and redo it */
451     map_way_select(map->appdata, way);
452     }
453     }
454     }
455    
456     /* -------------------------- way_node_cut ----------------------- */
457    
458     void map_edit_way_cut_highlight(map_t *map, map_item_t *item, gint x, gint y) {
459    
460     if(map_item_is_selected_way(map, item)) {
461     gint nx, ny, seg;
462     canvas_window2world(map->canvas, x, y, &nx, &ny);
463     seg = canvas_item_get_segment(item->item, nx, ny);
464     if(seg >= 0) {
465     gint x0, y0, x1, y1;
466     canvas_item_get_segment_pos(item->item, seg, &x0, &y0, &x1, &y1);
467    
468     gint width = (item->way->draw.flags &
469     OSM_DRAW_FLAG_BG)?
470     2*item->way->draw.bg.width:
471     3*item->way->draw.width;
472     map_hl_segment_draw(map, width, x0, y0, x1, y1);
473     }
474     } else if(map_item_is_selected_node(map, item)) {
475     node_t *nfirst = osm_way_get_first_node(map->selected.way);
476     node_t *nlast = osm_way_get_last_node(map->selected.way);
477    
478     /* cutting a way at its first or last node doesn't make much sense ... */
479     if((nfirst != item->node) && (nlast != item->node))
480     map_hl_cursor_draw(map, item->node->lpos.x, item->node->lpos.y,
481     TRUE, 2*map->style->node.radius);
482     }
483     }
484    
485     /* cut the currently selected way at the current cursor position */
486     void map_edit_way_cut(map_t *map, gint x, gint y) {
487    
488     /* check if we are still hovering above the selected way */
489 harbaum 15 map_item_t *item = map_real_item_at(map, x, y);
490 harbaum 1 if(item && (map_item_is_selected_way(map, item) ||
491     map_item_is_selected_node(map, item))) {
492     gboolean cut_at_node = map_item_is_selected_node(map, item);
493    
494     /* convert mouse position to canvas (world) position */
495     canvas_window2world(map->canvas, x, y, &x, &y);
496    
497     gint cut_at = -1;
498     way_t *way = NULL;
499     if(cut_at_node) {
500     printf(" cut at node\n");
501    
502     /* node must not be first or last node of way */
503     g_assert(map->selected.type == MAP_TYPE_WAY);
504    
505     if((osm_way_get_first_node(map->selected.way) != item->node) &&
506     (osm_way_get_last_node(map->selected.way) != item->node)) {
507     way = map->selected.way;
508    
509     cut_at = 0;
510     node_chain_t *chain = way->node_chain;
511     while(chain && chain->node != item->node) {
512     chain = chain->next;
513     cut_at++;
514     }
515    
516     } else
517     printf(" won't cut as it's last or first node\n");
518    
519     } else {
520     printf(" cut at segment\n");
521     cut_at = canvas_item_get_segment(item->item, x, y);
522     if(cut_at >= 0) way = item->way;
523     }
524    
525     if(way) {
526     /* create a duplicate of the currently selected way */
527     way_t *new = osm_way_new();
528    
529     /* if this is a closed way, reorder (rotate) it, so the */
530     /* place to cut is adjecent to the begin/end of the way. */
531     /* this prevents a cut polygon to be split into two ways */
532     g_assert(way->node_chain);
533     if(way->node_chain->node == osm_way_get_last_node(way)) {
534     printf("CLOSED WAY -> rotate by %d\n", cut_at);
535     osm_way_rotate(way, cut_at);
536     cut_at = 0;
537     }
538    
539     /* ------------ copy all tags ------------- */
540     new->tag = osm_tags_copy(way->tag, TRUE);
541    
542     /* ---- transfer relation membership from way to new ----- */
543     transfer_relations(map->appdata->osm, new, way);
544    
545     /* move parts of node_chain to the new way */
546     printf(" moving everthing after segment %d to new way\n", cut_at);
547    
548     node_chain_t *chain = way->node_chain;
549     while(cut_at--) {
550     g_assert(chain);
551     chain = chain->next;
552     }
553    
554     /* attach remaining nodes to new way */
555     new->node_chain = chain->next;
556    
557     /* terminate remainig chain on old way */
558     chain->next = NULL;
559    
560     /* if we cut at a node, this node is now part of both ways. so */
561     /* create a copy of the last node of the old way and prepend it to */
562     /* the new way */
563     if(cut_at_node) {
564     node_chain_t *first = g_new0(node_chain_t, 1);
565     first->next = new->node_chain;
566     first->node = osm_way_get_last_node(way);
567     first->node->ways++;
568     new->node_chain = first;
569     }
570    
571     /* now move the way itself into the main data structure */
572     osm_way_attach(map->appdata->osm, new);
573    
574     /* clear selection */
575     map_item_deselect(map->appdata);
576    
577     /* remove prior version of this way */
578     printf("remove visible version of way #%ld\n", way->id);
579     map_item_chain_destroy(&way->map_item_chain);
580    
581     /* swap chains of the old way is to be destroyed due to a lack */
582     /* of nodes */
583     if(osm_way_number_of_nodes(way) < 2) {
584     printf("swapping ways to avoid destruction of original way\n");
585     node_chain_t *tmp = way->node_chain;
586     way->node_chain = new->node_chain;
587     new->node_chain = tmp;
588     }
589    
590     /* the way may still only consist of a single node. */
591     /* remove it then */
592     if(osm_way_number_of_nodes(way) < 2) {
593     printf("original way has less than 2 nodes left, deleting it\n");
594     map_way_delete(map->appdata, way);
595     item = NULL;
596     } else {
597     printf("original way still has %d nodes\n",
598     osm_way_number_of_nodes(way));
599    
600     /* draw the updated old way */
601     josm_elemstyles_colorize_way(map->style, way);
602     map_way_draw(map, way);
603    
604     /* remember that the way needs to be uploaded */
605     way->flags |= OSM_FLAG_DIRTY;
606     }
607    
608     if(osm_way_number_of_nodes(new) < 2) {
609     printf("new way has less than 2 nodes, deleting it\n");
610     map_way_delete(map->appdata, new);
611     new = NULL;
612     } else {
613    
614     /* colorize the new way before drawing */
615     josm_elemstyles_colorize_way(map->style, new);
616     map_way_draw(map, new);
617     }
618    
619     /* put gui into idle state */
620     map_action_set(map->appdata, MAP_ACTION_IDLE);
621    
622     /* and redo selection if way still exists */
623     if(item)
624     map_way_select(map->appdata, way);
625     else if(new)
626     map_way_select(map->appdata, new);
627     }
628     }
629     }
630    
631     void map_edit_node_move(appdata_t *appdata, map_item_t *map_item,
632     gint ex, gint ey) {
633    
634     map_t *map = appdata->map;
635     osm_t *osm = appdata->osm;
636    
637     g_assert(map_item->type == MAP_TYPE_NODE);
638     node_t *node = map_item->node;
639    
640     printf("released dragged node #%ld\n", node->id);
641     printf(" was at %d %d (%f %f)\n",
642     node->lpos.x, node->lpos.y,
643     node->pos.lat, node->pos.lon);
644    
645    
646     /* check if it was dropped onto another node */
647     node_t *touchnode = map_hl_touchnode_get_node(map);
648     if(touchnode) {
649     map_hl_touchnode_clear(map);
650    
651     printf(" dropped onto node #%ld\n", touchnode->id);
652    
653     if(yes_no_f(GTK_WIDGET(appdata->window),
654     appdata, MISC_AGAIN_ID_JOIN_NODES, 0,
655     _("Join nodes?"),
656     _("Do you want to join the dragged node with the one "
657     "you dropped it on?"))) {
658    
659     /* the touchnode vanishes and is replaced by the node the */
660     /* user dropped onto it */
661    
662     /* use touchnodes position */
663     node->lpos = touchnode->lpos;
664     node->pos = touchnode->pos;
665    
666     way_t *way = appdata->osm->way;
667     while(way) {
668     node_chain_t *chain = way->node_chain;
669     while(chain) {
670     if(chain->node == touchnode) {
671     printf(" found node in way #%ld\n", way->id);
672    
673     /* replace by node */
674     chain->node = node;
675    
676     /* and adjust way references of both nodes */
677     node->ways++;
678     touchnode->ways--;
679    
680     way->flags |= OSM_FLAG_DIRTY;
681     }
682     chain = chain->next;
683     }
684     way = way->next;
685     }
686    
687     /* replace node in relations */
688     relation_t *relation = appdata->osm->relation;
689     while(relation) {
690     member_t *member = relation->member;
691     while(member) {
692     if(member->type == NODE && member->node == touchnode) {
693     printf(" found node in relation #%ld\n", relation->id);
694    
695     /* replace by node */
696     member->node = node;
697    
698     relation->flags |= OSM_FLAG_DIRTY;
699     }
700     member = member->next;
701     }
702     relation = relation->next;
703     }
704    
705     gboolean conflict = combine_tags(&node->tag, touchnode->tag);
706     touchnode->tag = NULL;
707    
708     /* touchnode must not have any references to ways anymore */
709     g_assert(!touchnode->ways);
710    
711     /* delete touchnode */
712     /* remove it visually from the screen */
713     map_item_chain_destroy(&touchnode->map_item_chain);
714    
715     /* and remove it from the data structures */
716     osm_node_remove_from_relation(appdata->osm, touchnode);
717     osm_node_delete(appdata->osm, &appdata->icon, touchnode, FALSE, TRUE);
718    
719     /* and open dialog to resolve tag collisions if necessary */
720     if(conflict)
721     messagef(GTK_WIDGET(appdata->window), _("Node tag conflict"),
722     _("The resulting node contains some conflicting tags. "
723     "Please solve these."));
724    
725     /* check whether this will also join two ways */
726     printf(" checking if node is end of way\n");
727     guint ways2join_cnt = 0;
728     way_t *ways2join[2] = { NULL, NULL };
729     way = appdata->osm->way;
730     while(way) {
731     if(osm_way_ends_with_node(way, node)) {
732     if(ways2join_cnt < 2)
733     ways2join[ways2join_cnt] = way;
734    
735     printf(" way #%ld ends with this node\n", way->id);
736     ways2join_cnt++;
737     }
738     way = way->next;
739     }
740    
741     if(ways2join_cnt > 2) {
742     messagef(GTK_WIDGET(appdata->window), _("Too many ways to join"),
743 achadwick 6 _("More than two ways now end on this node. Joining more "
744 harbaum 1 "than two ways is not yet implemented, sorry"));
745    
746     } else if(ways2join_cnt == 2) {
747     if(yes_no_f(GTK_WIDGET(appdata->window),
748     appdata, MISC_AGAIN_ID_JOIN_WAYS, 0,
749     _("Join ways?"),
750     _("Do you want to join the dragged way with the one "
751     "you dropped it on?"))) {
752    
753     printf(" about to join ways #%ld and #%ld\n",
754     ways2join[0]->id, ways2join[1]->id);
755    
756     /* way[1] gets destroyed and attached to way[0] */
757     /* so check if way[1] is selected and exchainge ways then */
758     /* so that way may stay selected */
759     if((map->selected.type == MAP_TYPE_WAY) &&
760     (map->selected.way == ways2join[1])) {
761     printf(" swapping ways to keep selected one alive\n");
762     way_t *tmp = ways2join[1];
763     ways2join[1] = ways2join[0];
764     ways2join[0] = tmp;
765     }
766    
767     /* take all nodes from way[1] and append them to way[0] */
768     /* check if we have to append or prepend to way[0] */
769     gboolean revert = FALSE;
770     if(ways2join[0]->node_chain->node == node) {
771     /* make "prepend" to be "append" by reverting way[0] */
772     printf(" target prepend -> revert\n");
773     revert = TRUE;
774     osm_way_revert(ways2join[0]);
775     }
776    
777     /* verify the common node is last in the target way */
778     node_chain_t *chain = ways2join[0]->node_chain;
779     while(chain->next) chain = chain->next;
780     g_assert(chain->node == node);
781     g_assert(!chain->next);
782    
783     /* common node must be first in the chain to attach */
784     if(ways2join[1]->node_chain->node != node) {
785     printf(" source revert\n");
786     osm_way_revert(ways2join[1]);
787     }
788    
789     /* verify the common node is first in the source way */
790     g_assert(ways2join[1]->node_chain->node == node);
791    
792     /* finally append source chain to target */
793     g_assert(!chain->next);
794     chain->next = ways2join[1]->node_chain->next;
795    
796     ways2join[1]->node_chain->next = NULL;
797    
798     /* transfer tags from touchnode to node */
799    
800     /* ---------- transfer tags from way[1] to way[0] ----------- */
801     gboolean conflict =
802     combine_tags(&ways2join[0]->tag, ways2join[1]->tag);
803     ways2join[1]->tag = NULL;
804    
805     /* ---- transfer relation membership from way[1] to way[0] ----- */
806     relation_chain_t *rchain =
807     osm_way_to_relation(appdata->osm, ways2join[1]);
808    
809     while(rchain) {
810     relation_chain_t *next = rchain->next;
811     printf("way[1] is part of relation #%ld\n", rchain->relation->id);
812    
813     /* make way[0] member of the same relation */
814    
815     /* walk member chain. save role of way[1] if its being found. */
816     /* end search either at end of chain or if way[0] was foind */
817     /* as it's already a member of that relation */
818     member_t **member = &rchain->relation->member;
819     char *role = NULL;
820     while(*member &&
821     !(((*member)->type == WAY) &&
822     ((*member)->way == ways2join[0]))) {
823    
824     /* save role of way[1] */
825     if(((*member)->type == WAY) && ((*member)->way == ways2join[0]))
826     role = (*member)->role;
827    
828     member = &(*member)->next;
829     }
830    
831     if(*member)
832     printf(" both ways were members of this relation\n");
833     else {
834     printf(" adding way[0] to relation\n");
835     *member = g_new0(member_t, 1);
836     (*member)->type = WAY;
837     (*member)->way = ways2join[0];
838     if(role) (*member)->role = g_strdup(role);
839     member = &(*member)->next;
840    
841     rchain->relation->flags |= OSM_FLAG_DIRTY;
842     }
843    
844     g_free(rchain);
845     rchain = next;
846     }
847    
848    
849     /* and open dialog to resolve tag collisions if necessary */
850     if(conflict)
851     messagef(GTK_WIDGET(appdata->window), _("Way tag conflict"),
852     _("The resulting way contains some conflicting tags. "
853     "Please solve these."));
854    
855     ways2join[0]->flags |= OSM_FLAG_DIRTY;
856     map_way_delete(appdata, ways2join[1]);
857     }
858     }
859     }
860     } else {
861    
862     /* finally update dragged nodes position */
863    
864     /* convert mouse position to canvas (world) position */
865     gint x, y;
866     canvas_window2world(map->canvas, ex, ey, &x, &y);
867     if(!osm_position_within_bounds(appdata->osm, x, y)) {
868     map_outside_error(appdata);
869     return;
870     }
871    
872     node->lpos.x = x;
873     node->lpos.y = y;
874    
875     /* convert screen position back to ll */
876     lpos2pos(osm->bounds, &node->lpos, &node->pos);
877    
878     printf(" now at %d %d (%f %f)\n",
879     node->lpos.x, node->lpos.y, node->pos.lat, node->pos.lon);
880     }
881    
882     /* now update the visual representation of the node */
883    
884     map_item_chain_destroy(&node->map_item_chain);
885     map_node_draw(map, node);
886    
887     /* visually update ways, node is part of */
888     way_t *way = osm->way;
889     while(way) {
890     if(osm_node_in_way(way, node)) {
891     printf(" node is part of way #%ld, redraw!\n", way->id);
892    
893     /* remove prior version of this way */
894     map_item_chain_destroy(&way->map_item_chain);
895    
896     /* draw current way */
897     josm_elemstyles_colorize_way(map->style, way);
898     map_way_draw(map, way);
899     }
900    
901     way = way->next;
902     }
903    
904     /* and mark the node as dirty */
905     node->flags |= OSM_FLAG_DIRTY;
906    
907     /* update highlight */
908     map_highlight_refresh(appdata);
909     }
910    
911     /* -------------------------- way_reverse ----------------------- */
912    
913     /* called from the "reverse" icon */
914     void map_edit_way_reverse(appdata_t *appdata) {
915     /* work on local copy since de-selecting destroys the selection */
916     map_item_t item = appdata->map->selected;
917    
918     /* deleting the selected item de-selects it ... */
919     map_item_deselect(appdata);
920    
921     g_assert(item.type == MAP_TYPE_WAY);
922    
923     osm_way_revert(item.way);
924     item.way->flags |= OSM_FLAG_DIRTY;
925    
926     map_way_select(appdata, item.way);
927     }
928