|
GRASS Programmer's Manual
6.5.svn(2012)-r51648
|
00001 00020 #include <stdlib.h> 00021 #include <math.h> 00022 #include <grass/gis.h> 00023 #include <grass/Vect.h> 00024 #include <grass/glocale.h> 00025 00026 /* TODO: 3D support 00027 * 00028 * atan2() gives angle from x-axis 00029 * this is unambiguous only in 2D, not in 3D 00030 * 00031 * one possibility would be to store unit vectors of length 1 00032 * in struct XPNT 00033 * double a1[3], a2[3]; 00034 * 00035 * length = sqrt(dx * dx + dy * dy + dz * dz); 00036 * dx /= length; dy /= length; dz /=length; 00037 * a1[0] = dx; a1[1] = dy; a1[2] = dz; 00038 * 00039 * get second dx, dy, dz 00040 * length = sqrt(dx * dx + dy * dy + dz * dz); 00041 * dx /= length; dy /= length; dz /=length; 00042 * a2[0] = dx; a2[1] = dy; a2[2] = dz; 00043 * 00044 * equal angles 00045 * if (a1[0] == a2[0] && a1[1] == a2[1] && a1[2] == a2[2]) 00046 * 00047 * disadvantage: increased memory consumption 00048 * 00049 * new function Vect_break_faces() ? 00050 * 00051 */ 00052 00053 typedef struct 00054 { 00055 double x, y; 00056 double a1, a2; /* angles */ 00057 char cross; /* 0 - do not break, 1 - break */ 00058 char used; /* 0 - was not used to break line, 1 - was used to break line 00059 * this is stored because points are automatically marked as cross, even if not used 00060 * later to break lines */ 00061 } XPNT; 00062 00063 static int fpoint; 00064 00065 /* Function called from RTreeSearch for point found */ 00066 void srch(int id, int *arg) 00067 { 00068 fpoint = id; 00069 } 00070 00088 void 00089 Vect_break_polygons(struct Map_info *Map, int type, struct Map_info *Err) 00090 { 00091 struct line_pnts *BPoints, *Points; 00092 struct line_cats *Cats; 00093 int i, j, k, ret, ltype, broken, last, nlines; 00094 int nbreaks; 00095 struct Node *RTree; 00096 int apoints, npoints, nallpoints, nmarks; 00097 XPNT *XPnts; 00098 struct Rect rect; 00099 double dx, dy, a1 = 0, a2 = 0; 00100 int closed, last_point, cross; 00101 00102 RTree = RTreeNewIndex(); 00103 00104 BPoints = Vect_new_line_struct(); 00105 Points = Vect_new_line_struct(); 00106 Cats = Vect_new_cats_struct(); 00107 00108 nlines = Vect_get_num_lines(Map); 00109 00110 G_debug(3, "nlines = %d", nlines); 00111 /* Go through all lines in vector, and add each point to structure of points, 00112 * if such point already exists check angles of segments and if differ mark for break */ 00113 00114 apoints = 0; 00115 nmarks = 0; 00116 npoints = 1; /* index starts from 1 ! */ 00117 nallpoints = 0; 00118 XPnts = NULL; 00119 00120 G_verbose_message(_("Break polygons Pass 1: select break points")); 00121 00122 for (i = 1; i <= nlines; i++) { 00123 G_percent(i, nlines, 1); 00124 G_debug(3, "i = %d", i); 00125 if (!Vect_line_alive(Map, i)) 00126 continue; 00127 00128 ltype = Vect_read_line(Map, Points, Cats, i); 00129 if (!(ltype & type)) 00130 continue; 00131 00132 /* This would be confused by duplicate coordinates (angle cannot be calculated) -> 00133 * prune line first */ 00134 Vect_line_prune(Points); 00135 00136 /* If first and last point are identical it is close polygon, we dont need to register last point 00137 * and we can calculate angle for first. 00138 * If first and last point are not identical we have to mark for break both */ 00139 last_point = Points->n_points - 1; 00140 if (Points->x[0] == Points->x[last_point] && 00141 Points->y[0] == Points->y[last_point]) 00142 closed = 1; 00143 else 00144 closed = 0; 00145 00146 for (j = 0; j < Points->n_points; j++) { 00147 G_debug(3, "j = %d", j); 00148 nallpoints++; 00149 00150 if (j == last_point && closed) 00151 continue; /* do not register last of close polygon */ 00152 00153 /* Box */ 00154 rect.boundary[0] = Points->x[j]; 00155 rect.boundary[3] = Points->x[j]; 00156 rect.boundary[1] = Points->y[j]; 00157 rect.boundary[4] = Points->y[j]; 00158 rect.boundary[2] = 0; 00159 rect.boundary[5] = 0; 00160 00161 /* Already in DB? */ 00162 fpoint = -1; 00163 RTreeSearch(RTree, &rect, (void *)srch, 0); 00164 G_debug(3, "fpoint = %d", fpoint); 00165 00166 if (Points->n_points <= 2 || 00167 (!closed && (j == 0 || j == last_point))) { 00168 cross = 1; /* mark for cross in any case */ 00169 } 00170 else { /* calculate angles */ 00171 cross = 0; 00172 if (j == 0 && closed) { /* closed polygon */ 00173 dx = Points->x[last_point] - Points->x[0]; 00174 dy = Points->y[last_point] - Points->y[0]; 00175 a1 = atan2(dy, dx); 00176 dx = Points->x[1] - Points->x[0]; 00177 dy = Points->y[1] - Points->y[0]; 00178 a2 = atan2(dy, dx); 00179 } 00180 else { 00181 dx = Points->x[j - 1] - Points->x[j]; 00182 dy = Points->y[j - 1] - Points->y[j]; 00183 a1 = atan2(dy, dx); 00184 dx = Points->x[j + 1] - Points->x[j]; 00185 dy = Points->y[j + 1] - Points->y[j]; 00186 a2 = atan2(dy, dx); 00187 } 00188 } 00189 00190 if (fpoint > 0) { /* Found */ 00191 if (XPnts[fpoint].cross == 1) 00192 continue; /* already marked */ 00193 00194 /* Check angles */ 00195 if (cross) { 00196 XPnts[fpoint].cross = 1; 00197 nmarks++; 00198 } 00199 else { 00200 G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1, 00201 XPnts[fpoint].a1, a2, XPnts[fpoint].a2); 00202 if ((a1 == XPnts[fpoint].a1 && a2 == XPnts[fpoint].a2) || (a1 == XPnts[fpoint].a2 && a2 == XPnts[fpoint].a1)) { /* identical */ 00203 00204 } 00205 else { 00206 XPnts[fpoint].cross = 1; 00207 nmarks++; 00208 } 00209 } 00210 } 00211 else { 00212 /* Add to tree and to structure */ 00213 RTreeInsertRect(&rect, npoints, &RTree, 0); 00214 if (npoints >= apoints) { 00215 apoints += 10000; 00216 XPnts = 00217 (XPNT *) G_realloc(XPnts, 00218 (apoints + 1) * sizeof(XPNT)); 00219 } 00220 XPnts[npoints].x = Points->x[j]; 00221 XPnts[npoints].y = Points->y[j]; 00222 XPnts[npoints].used = 0; 00223 if (j == 0 || j == (Points->n_points - 1) || 00224 Points->n_points < 3) { 00225 XPnts[npoints].a1 = 0; 00226 XPnts[npoints].a2 = 0; 00227 XPnts[npoints].cross = 1; 00228 nmarks++; 00229 } 00230 else { 00231 XPnts[npoints].a1 = a1; 00232 XPnts[npoints].a2 = a2; 00233 XPnts[npoints].cross = 0; 00234 } 00235 00236 npoints++; 00237 } 00238 } 00239 } 00240 00241 /* G_sleep (10); */ 00242 00243 nbreaks = 0; 00244 00245 /* Second loop through lines (existing when loop is started, no need to process lines written again) 00246 * and break at points marked for break */ 00247 00248 G_verbose_message(_("Break polygons Pass 2: break at selected points")); 00249 00250 for (i = 1; i <= nlines; i++) { 00251 int n_orig_points; 00252 00253 G_percent(i, nlines, 1); 00254 G_debug(3, "i = %d", i); 00255 if (!Vect_line_alive(Map, i)) 00256 continue; 00257 00258 ltype = Vect_read_line(Map, Points, Cats, i); 00259 if (!(ltype & type)) 00260 continue; 00261 if (!(ltype & GV_LINES)) 00262 continue; /* Nonsense to break points */ 00263 00264 /* Duplicates would result in zero length lines -> prune line first */ 00265 n_orig_points = Points->n_points; 00266 Vect_line_prune(Points); 00267 00268 broken = 0; 00269 last = 0; 00270 G_debug(3, "n_points = %d", Points->n_points); 00271 for (j = 1; j < Points->n_points; j++) { 00272 G_debug(3, "j = %d", j); 00273 nallpoints++; 00274 00275 /* Box */ 00276 rect.boundary[0] = Points->x[j]; 00277 rect.boundary[3] = Points->x[j]; 00278 rect.boundary[1] = Points->y[j]; 00279 rect.boundary[4] = Points->y[j]; 00280 rect.boundary[2] = 0; 00281 rect.boundary[5] = 0; 00282 00283 if (Points->n_points <= 1 || 00284 (j == (Points->n_points - 1) && !broken)) 00285 break; 00286 /* One point only or 00287 * last point and line is not broken, do nothing */ 00288 00289 RTreeSearch(RTree, &rect, (void *)srch, 0); 00290 G_debug(3, "fpoint = %d", fpoint); 00291 00292 if (XPnts[fpoint].cross) { /* realy use to break line */ 00293 XPnts[fpoint].used = 1; 00294 } 00295 00296 /* break or write last segment of broken line */ 00297 if ((j == (Points->n_points - 1) && broken) || 00298 XPnts[fpoint].cross) { 00299 Vect_reset_line(BPoints); 00300 for (k = last; k <= j; k++) { 00301 Vect_append_point(BPoints, Points->x[k], Points->y[k], 00302 Points->z[k]); 00303 } 00304 00305 /* Result may collapse to one point */ 00306 Vect_line_prune(BPoints); 00307 if (BPoints->n_points > 1) { 00308 ret = Vect_write_line(Map, ltype, BPoints, Cats); 00309 G_debug(3, 00310 "Line %d written j = %d n_points(orig,pruned) = %d n_points(new) = %d", 00311 ret, j, Points->n_points, BPoints->n_points); 00312 } 00313 00314 if (!broken) 00315 Vect_delete_line(Map, i); /* not yet deleted */ 00316 00317 last = j; 00318 broken = 1; 00319 nbreaks++; 00320 } 00321 } 00322 if (!broken && n_orig_points > Points->n_points) { /* was pruned before -> rewrite */ 00323 if (Points->n_points > 1) { 00324 Vect_rewrite_line(Map, i, ltype, Points, Cats); 00325 G_debug(3, "Line %d pruned, npoints = %d", i, 00326 Points->n_points); 00327 } 00328 else { 00329 Vect_delete_line(Map, i); 00330 G_debug(3, "Line %d was deleted", i); 00331 } 00332 } 00333 else { 00334 G_debug(3, "Line %d was not changed", i); 00335 } 00336 } 00337 00338 /* Write points on breaks */ 00339 if (Err) { 00340 Vect_reset_cats(Cats); 00341 for (i = 1; i < npoints; i++) { 00342 if (XPnts[i].used) { 00343 Vect_reset_line(Points); 00344 Vect_append_point(Points, XPnts[i].x, XPnts[i].y, 0); 00345 Vect_write_line(Err, GV_POINT, Points, Cats); 00346 } 00347 } 00348 } 00349 00350 G_free(XPnts); 00351 RTreeDestroyNode(RTree); 00352 }