|
GRASS Programmer's Manual
6.5.svn(2012)-r51648
|
00001 00020 #include <math.h> 00021 #include <grass/gis.h> 00022 #include <grass/Vect.h> 00023 #include <grass/glocale.h> 00024 00025 /* function prototypes */ 00026 static int sort_new(const void *pa, const void *pb); 00027 00028 /* Vertex */ 00029 typedef struct 00030 { 00031 double x, y; 00032 int anchor; /* 0 - anchor, do not snap this point, that means snap others to this */ 00033 /* >0 - index of anchor to which snap this point */ 00034 /* -1 - init value */ 00035 } XPNT; 00036 00037 typedef struct 00038 { 00039 int anchor; 00040 double along; 00041 } NEW; 00042 00043 /* This function is called by RTreeSearch() to add selected node/line/area/isle to thelist */ 00044 int add_item(int id, struct ilist *list) 00045 { 00046 dig_list_add(list, id); 00047 return 1; 00048 } 00049 00068 /* As mentioned above, lines are not necessarily snapped to nearest vertex! For example: 00069 | 00070 | 1 line 3 is snapped to line 1, 00071 | then line 2 is not snapped to common node at lines 1 and 3, 00072 because it is already outside of threshold 00073 ----------- 3 00074 00075 | 00076 | 2 00077 | 00078 */ 00079 void 00080 Vect_snap_lines_list(struct Map_info *Map, struct ilist *List_lines, 00081 double thresh, struct Map_info *Err) 00082 { 00083 struct line_pnts *Points, *NPoints; 00084 struct line_cats *Cats; 00085 int line, ltype, line_idx; 00086 double thresh2; 00087 00088 struct Node *RTree; 00089 int point; /* index in points array */ 00090 int nanchors, ntosnap; /* number of anchors and number of points to be snapped */ 00091 int nsnapped, ncreated; /* number of snapped verices, number of new vertices (on segments) */ 00092 int apoints, npoints, nvertices; /* number of allocated points, registered points, vertices */ 00093 XPNT *XPnts; /* Array of points */ 00094 NEW *New = NULL; /* Array of new points */ 00095 int anew = 0, nnew; /* allocated new points , number of new points */ 00096 struct Rect rect; 00097 struct ilist *List; 00098 int *Index = NULL; /* indexes of anchors for vertices */ 00099 int aindex = 0; /* allocated Index */ 00100 00101 if (List_lines->n_values < 1) 00102 return; 00103 00104 Points = Vect_new_line_struct(); 00105 NPoints = Vect_new_line_struct(); 00106 Cats = Vect_new_cats_struct(); 00107 List = Vect_new_list(); 00108 RTree = RTreeNewIndex(); 00109 00110 thresh2 = thresh * thresh; 00111 00112 /* Go through all lines in vector, and add each point to structure of points */ 00113 apoints = 0; 00114 point = 1; /* index starts from 1 ! */ 00115 nvertices = 0; 00116 XPnts = NULL; 00117 00118 G_verbose_message(_("Snap vertices Pass 1: select points")); 00119 for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) { 00120 int v; 00121 00122 G_percent(line_idx, List_lines->n_values, 2); 00123 00124 line = List_lines->value[line_idx]; 00125 00126 G_debug(3, "line = %d", line); 00127 if (!Vect_line_alive(Map, line)) 00128 continue; 00129 00130 ltype = Vect_read_line(Map, Points, Cats, line); 00131 00132 for (v = 0; v < Points->n_points; v++) { 00133 G_debug(3, " vertex v = %d", v); 00134 nvertices++; 00135 00136 /* Box */ 00137 rect.boundary[0] = Points->x[v]; 00138 rect.boundary[3] = Points->x[v]; 00139 rect.boundary[1] = Points->y[v]; 00140 rect.boundary[4] = Points->y[v]; 00141 rect.boundary[2] = 0; 00142 rect.boundary[5] = 0; 00143 00144 /* Already registered ? */ 00145 Vect_reset_list(List); 00146 RTreeSearch(RTree, &rect, (void *)add_item, List); 00147 G_debug(3, "List : nvalues = %d", List->n_values); 00148 00149 if (List->n_values == 0) { /* Not found */ 00150 /* Add to tree and to structure */ 00151 RTreeInsertRect(&rect, point, &RTree, 0); 00152 if ((point - 1) == apoints) { 00153 apoints += 10000; 00154 XPnts = 00155 (XPNT *) G_realloc(XPnts, 00156 (apoints + 1) * sizeof(XPNT)); 00157 } 00158 XPnts[point].x = Points->x[v]; 00159 XPnts[point].y = Points->y[v]; 00160 XPnts[point].anchor = -1; 00161 point++; 00162 } 00163 } 00164 } 00165 G_percent(line_idx, List_lines->n_values, 2); /* finish it */ 00166 00167 npoints = point - 1; 00168 00169 /* Go through all registered points and if not yet marked mark it as anchor and assign this anchor 00170 * to all not yet marked points in threshold */ 00171 00172 G_verbose_message(_("Snap vertices Pass 2: assign anchor vertices")); 00173 00174 nanchors = ntosnap = 0; 00175 for (point = 1; point <= npoints; point++) { 00176 int i; 00177 00178 G_percent(point, npoints, 2); 00179 00180 G_debug(3, " point = %d", point); 00181 00182 if (XPnts[point].anchor >= 0) 00183 continue; 00184 00185 XPnts[point].anchor = 0; /* make it anchor */ 00186 nanchors++; 00187 00188 /* Find points in threshold */ 00189 rect.boundary[0] = XPnts[point].x - thresh; 00190 rect.boundary[3] = XPnts[point].x + thresh; 00191 rect.boundary[1] = XPnts[point].y - thresh; 00192 rect.boundary[4] = XPnts[point].y + thresh; 00193 rect.boundary[2] = 0; 00194 rect.boundary[5] = 0; 00195 00196 Vect_reset_list(List); 00197 RTreeSearch(RTree, &rect, (void *)add_item, List); 00198 G_debug(4, " %d points in threshold box", List->n_values); 00199 00200 for (i = 0; i < List->n_values; i++) { 00201 int pointb; 00202 double dx, dy, dist2; 00203 00204 pointb = List->value[i]; 00205 if (pointb == point) 00206 continue; 00207 00208 dx = XPnts[pointb].x - XPnts[point].x; 00209 dy = XPnts[pointb].y - XPnts[point].y; 00210 dist2 = dx * dx + dy * dy; 00211 00212 if (dist2 > thresh2) /* outside threshold */ 00213 continue; 00214 00215 /* doesn't have an anchor yet */ 00216 if (XPnts[pointb].anchor == -1) { 00217 XPnts[pointb].anchor = point; 00218 ntosnap++; 00219 } 00220 else if (XPnts[pointb].anchor > 0) { /* check distance to previously assigned anchor */ 00221 double dist2_a; 00222 00223 dx = XPnts[XPnts[pointb].anchor].x - XPnts[pointb].x; 00224 dy = XPnts[XPnts[pointb].anchor].y - XPnts[pointb].y; 00225 dist2_a = dx * dx + dy * dy; 00226 00227 /* replace old anchor */ 00228 if (dist2 < dist2_a) { 00229 XPnts[pointb].anchor = point; 00230 } 00231 } 00232 } 00233 } 00234 00235 /* Go through all lines and: 00236 * 1) for all vertices: if not anchor snap it to its anchor 00237 * 2) for all segments: snap it to all anchors in threshold (except anchors of vertices of course) */ 00238 00239 nsnapped = ncreated = 0; 00240 00241 G_verbose_message(_("Snap vertices Pass 3: snap to assigned points")); 00242 00243 for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) { 00244 int v, spoint, anchor; 00245 int changed = 0; 00246 00247 G_percent(line_idx, List_lines->n_values, 2); 00248 00249 line = List_lines->value[line_idx]; 00250 00251 G_debug(3, "line = %d", line); 00252 if (!Vect_line_alive(Map, line)) 00253 continue; 00254 00255 ltype = Vect_read_line(Map, Points, Cats, line); 00256 00257 if (Points->n_points >= aindex) { 00258 aindex = Points->n_points; 00259 Index = (int *)G_realloc(Index, aindex * sizeof(int)); 00260 } 00261 00262 /* Snap all vertices */ 00263 for (v = 0; v < Points->n_points; v++) { 00264 /* Box */ 00265 rect.boundary[0] = Points->x[v]; 00266 rect.boundary[3] = Points->x[v]; 00267 rect.boundary[1] = Points->y[v]; 00268 rect.boundary[4] = Points->y[v]; 00269 rect.boundary[2] = 0; 00270 rect.boundary[5] = 0; 00271 00272 /* Find point ( should always find one point ) */ 00273 Vect_reset_list(List); 00274 00275 RTreeSearch(RTree, &rect, (void *)add_item, List); 00276 00277 spoint = List->value[0]; 00278 anchor = XPnts[spoint].anchor; 00279 00280 if (anchor > 0) { /* to be snapped */ 00281 Points->x[v] = XPnts[anchor].x; 00282 Points->y[v] = XPnts[anchor].y; 00283 nsnapped++; 00284 changed = 1; 00285 Index[v] = anchor; /* point on new location */ 00286 } 00287 else { 00288 Index[v] = spoint; /* old point */ 00289 } 00290 } 00291 00292 /* New points */ 00293 Vect_reset_line(NPoints); 00294 00295 /* Snap all segments to anchors in threshold */ 00296 for (v = 0; v < Points->n_points - 1; v++) { 00297 int i; 00298 double x1, x2, y1, y2, xmin, xmax, ymin, ymax; 00299 00300 G_debug(3, " segment = %d end anchors : %d %d", v, Index[v], 00301 Index[v + 1]); 00302 00303 x1 = Points->x[v]; 00304 x2 = Points->x[v + 1]; 00305 y1 = Points->y[v]; 00306 y2 = Points->y[v + 1]; 00307 00308 Vect_append_point(NPoints, Points->x[v], Points->y[v], 00309 Points->z[v]); 00310 00311 /* Box */ 00312 if (x1 <= x2) { 00313 xmin = x1; 00314 xmax = x2; 00315 } 00316 else { 00317 xmin = x2; 00318 xmax = x1; 00319 } 00320 if (y1 <= y2) { 00321 ymin = y1; 00322 ymax = y2; 00323 } 00324 else { 00325 ymin = y2; 00326 ymax = y1; 00327 } 00328 00329 rect.boundary[0] = xmin - thresh; 00330 rect.boundary[3] = xmax + thresh; 00331 rect.boundary[1] = ymin - thresh; 00332 rect.boundary[4] = ymax + thresh; 00333 rect.boundary[2] = 0; 00334 rect.boundary[5] = 0; 00335 00336 /* Find points */ 00337 Vect_reset_list(List); 00338 RTreeSearch(RTree, &rect, (void *)add_item, List); 00339 00340 G_debug(3, " %d points in box", List->n_values); 00341 00342 /* Snap to anchor in threshold different from end points */ 00343 nnew = 0; 00344 for (i = 0; i < List->n_values; i++) { 00345 double dist2, along; 00346 00347 spoint = List->value[i]; 00348 G_debug(4, " spoint = %d anchor = %d", spoint, 00349 XPnts[spoint].anchor); 00350 00351 if (spoint == Index[v] || spoint == Index[v + 1]) 00352 continue; /* end point */ 00353 if (XPnts[spoint].anchor > 0) 00354 continue; /* point is not anchor */ 00355 00356 /* Check the distance */ 00357 dist2 = 00358 dig_distance2_point_to_line(XPnts[spoint].x, 00359 XPnts[spoint].y, 0, x1, y1, 0, 00360 x2, y2, 0, 0, NULL, NULL, 00361 NULL, &along, NULL); 00362 00363 G_debug(4, " distance = %lf", sqrt(dist2)); 00364 00365 if (dist2 <= thresh2) { 00366 G_debug(4, " anchor in thresh, along = %lf", along); 00367 00368 if (nnew == anew) { 00369 anew += 100; 00370 New = (NEW *) G_realloc(New, anew * sizeof(NEW)); 00371 } 00372 New[nnew].anchor = spoint; 00373 New[nnew].along = along; 00374 nnew++; 00375 } 00376 } 00377 G_debug(3, " nnew = %d", nnew); 00378 /* insert new vertices */ 00379 if (nnew > 0) { 00380 /* sort by distance along the segment */ 00381 qsort(New, sizeof(char) * nnew, sizeof(NEW), sort_new); 00382 00383 for (i = 0; i < nnew; i++) { 00384 anchor = New[i].anchor; 00385 /* Vect_line_insert_point ( Points, ++v, XPnts[anchor].x, XPnts[anchor].y, 0); */ 00386 Vect_append_point(NPoints, XPnts[anchor].x, 00387 XPnts[anchor].y, 0); 00388 ncreated++; 00389 } 00390 changed = 1; 00391 } 00392 } 00393 00394 /* append end point */ 00395 v = Points->n_points - 1; 00396 Vect_append_point(NPoints, Points->x[v], Points->y[v], Points->z[v]); 00397 00398 if (changed) { /* rewrite the line */ 00399 Vect_line_prune(NPoints); /* remove duplicates */ 00400 if (NPoints->n_points > 1 || ltype & GV_LINES) { 00401 Vect_rewrite_line(Map, line, ltype, NPoints, Cats); 00402 } 00403 else { 00404 Vect_delete_line(Map, line); 00405 } 00406 if (Err) { 00407 Vect_write_line(Err, ltype, Points, Cats); 00408 } 00409 } 00410 } /* for each line */ 00411 G_percent(line_idx, List_lines->n_values, 2); /* finish it */ 00412 00413 Vect_destroy_line_struct(Points); 00414 Vect_destroy_line_struct(NPoints); 00415 Vect_destroy_cats_struct(Cats); 00416 G_free(XPnts); 00417 G_free(Index); 00418 G_free(New); 00419 RTreeDestroyNode(RTree); 00420 00421 G_verbose_message(_("Snapped vertices: %d"), nsnapped); 00422 G_verbose_message(_("New vertices: %d"), ncreated); 00423 } 00424 00425 /* for qsort */ 00426 static int sort_new(const void *pa, const void *pb) 00427 { 00428 NEW *p1 = (NEW *) pa; 00429 NEW *p2 = (NEW *) pb; 00430 00431 if (p1->along < p2->along) 00432 return -1; 00433 if (p1->along > p2->along) 00434 return 1; 00435 return 1; 00436 } 00437 00450 void 00451 Vect_snap_lines(struct Map_info *Map, int type, double thresh, 00452 struct Map_info *Err) 00453 { 00454 int line, nlines, ltype; 00455 00456 struct ilist *List; 00457 00458 List = Vect_new_list(); 00459 00460 nlines = Vect_get_num_lines(Map); 00461 00462 for (line = 1; line <= nlines; line++) { 00463 G_debug(3, "line = %d", line); 00464 00465 if (!Vect_line_alive(Map, line)) 00466 continue; 00467 00468 ltype = Vect_read_line(Map, NULL, NULL, line); 00469 00470 if (!(ltype & type)) 00471 continue; 00472 00473 /* Vect_list_append(List, line); */ 00474 dig_list_add(List, line); 00475 } 00476 00477 Vect_snap_lines_list(Map, List, thresh, Err); 00478 00479 Vect_destroy_list(List); 00480 00481 return; 00482 }