GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
break_polygons.c
Go to the documentation of this file.
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 }