GRASS Programmer's Manual  6.4.1(2011)
merge_lines.c
Go to the documentation of this file.
00001 
00018 #include <grass/config.h>
00019 #include <stdlib.h>
00020 #include <math.h>
00021 #include <grass/gis.h>
00022 #include <grass/Vect.h>
00023 #include <grass/glocale.h>
00024 
00044 int Vect_merge_lines(struct Map_info *Map, int type, int *new_lines,
00045                      struct Map_info *Err)
00046 {
00047     int line, nlines, i, c, first, last, next_line, curr_line;
00048     int merged = 0, newl = 0;
00049     int next_node, direction, node_n_lines, same_type;
00050     struct Plus_head *Plus;
00051     struct ilist *List;
00052     struct line_pnts *MPoints, *Points;
00053     struct line_cats *MCats, *Cats;
00054     struct P_line *Line;
00055 
00056     if ((type & GV_BOUNDARY) && (type & GV_LINE)) {
00057         G_warning
00058             ("Merging is done only with either lines or boundaries, not both types at the same time");
00059         return 0;
00060     }
00061     if (!(type & GV_BOUNDARY) && !(type & GV_LINE)) {
00062         G_warning
00063             ("Merging is done with lines or boundaries only, not with other types");
00064         return 0;
00065     }
00066 
00067     Plus = &(Map->plus);
00068     nlines = Vect_get_num_lines(Map);
00069 
00070     Points = Vect_new_line_struct();
00071     Cats = Vect_new_cats_struct();
00072     MPoints = Vect_new_line_struct();
00073     MCats = Vect_new_cats_struct();
00074     List = Vect_new_list();
00075 
00076     for (line = 1; line <= nlines; line++) {
00077         G_percent(line, nlines, 2);
00078 
00079         if (!Vect_line_alive(Map, line))
00080             continue;
00081 
00082         Line = Plus->Line[line];
00083 
00084         if (!(Line->type & type))
00085             continue;
00086 
00087         /* special cases:
00088          *  - loop back to start boundary via several other boundaries
00089          *  - one boundary forming closed loop
00090          *  - node with 3 entries but only 2 boundaries, one of them connecting twice,
00091          *    the other one must then be topologically incorrect in case of boundary */
00092 
00093         /* go backward as long as there is only one other line/boundary at the current node */
00094         G_debug(3, "go backward");
00095         next_node = Line->N1;
00096         first = -line;
00097         while (1) {
00098             node_n_lines = Vect_get_node_n_lines(Map, next_node);
00099             same_type = 0;
00100             next_line = first;
00101             for (i = 0; i < node_n_lines; i++) {
00102                 curr_line = Vect_get_node_line(Map, next_node, i);
00103                 if ((Plus->Line[abs(curr_line)]->type & type)) {
00104                     same_type++;
00105                     if (abs(curr_line) != abs(first))
00106                         next_line = curr_line;
00107                 }
00108             }
00109             if (same_type == 2 && abs(next_line) != abs(first) &&
00110                 abs(next_line) != line) {
00111                 first = next_line;
00112 
00113                 if (first < 0)
00114                     next_node = Plus->Line[-first]->N1;
00115                 else
00116                     next_node = Plus->Line[first]->N2;
00117             }
00118             else
00119                 break;
00120         }
00121 
00122         /* go forward as long as there is only one other line/boundary at the current node */
00123         G_debug(3, "go forward");
00124 
00125         /* reverse direction */
00126         last = -first;
00127 
00128         if (last < 0)
00129             next_node = Plus->Line[-last]->N1;
00130         else
00131             next_node = Plus->Line[last]->N2;
00132 
00133         Vect_reset_list(List);
00134         while (1) {
00135             Vect_list_append(List, last);
00136             node_n_lines = Vect_get_node_n_lines(Map, next_node);
00137             same_type = 0;
00138             next_line = last;
00139             for (i = 0; i < node_n_lines; i++) {
00140                 curr_line = Vect_get_node_line(Map, next_node, i);
00141                 if ((Plus->Line[abs(curr_line)]->type & type)) {
00142                     same_type++;
00143                     if (abs(curr_line) != abs(last))
00144                         next_line = curr_line;
00145                 }
00146             }
00147 
00148             if (same_type == 2 && abs(next_line) != abs(last) &&
00149                 abs(next_line) != abs(first)) {
00150                 last = next_line;
00151 
00152                 if (last < 0)
00153                     next_node = Plus->Line[-last]->N1;
00154                 else
00155                     next_node = Plus->Line[last]->N2;
00156             }
00157             else
00158                 break;
00159         }
00160 
00161         /* merge lines */
00162         if (List->n_values > 1) {
00163             G_debug(3, "merge %d lines", List->n_values);
00164             Vect_reset_line(MPoints);
00165             Vect_reset_cats(MCats);
00166 
00167             for (i = 0; i < List->n_values; i++) {
00168                 Vect_reset_line(Points);
00169                 Vect_reset_cats(Cats);
00170                 Vect_read_line(Map, Points, Cats, abs(List->value[i]));
00171                 direction = (List->value[i] < 0 ? GV_BACKWARD : GV_FORWARD);
00172                 Vect_append_points(MPoints, Points, direction);
00173                 MPoints->n_points--;
00174                 for (c = 0; c < Cats->n_cats; c++) {
00175                     Vect_cat_set(MCats, Cats->field[c], Cats->cat[c]);
00176                 }
00177                 if (Err) {
00178                     /* write out lines/boundaries to be merged */
00179                     Vect_write_line(Err, type, Points, Cats);
00180                 }
00181                 Vect_delete_line(Map, abs(List->value[i]));
00182             }
00183             MPoints->n_points++;
00184             Vect_write_line(Map, type, MPoints, MCats);
00185             merged += List->n_values;
00186             newl++;
00187         }
00188 
00189         nlines = Vect_get_num_lines(Map);
00190     }
00191 
00192     G_verbose_message(_("%d boundaries merged"), merged);
00193     G_verbose_message(_("%d new boundaries"), newl);
00194 
00195     if (new_lines)
00196         *new_lines = newl;
00197 
00198     return merged;
00199 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines