123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- #define OUTLINE
- #include <stdlib.h>
- #include <grass/gis.h>
- #include <grass/glocale.h>
- #include "globals.h"
- #include "local_proto.h"
- #define V Region.vertex /* converted vertex list */
- #define VN Region.vertex_npoints
- #define P Region.perimeter /* perimeter point list */
- #define PN Region.perimeter_npoints
- #define A Region.point
- #define AN Region.npoints
- #define extrema(x,y,z) (((x<y)&&(z<y))||((x>y)&&(z>y)))
- #define non_extrema(x,y,z) (((x<y)&&(y<z))||((x>y)&&(y>z)))
- int outline(void)
- {
- int first;
- int skip; /* boolean */
- int np; /* perimeter estimate */
- POINT tmp[MAX_VERTEX]; /* temp vertex list */
- int cur;
- int prev;
- int next;
- double tmp_n, tmp_e;
- POINT temp;
- /* convert alarm area points to data row/col verticies */
- Menu_msg("Preparing outline...");
- for (cur = 0; cur < AN; cur++) {
- temp.y = view_to_row(Region.view, A[cur].y);
- temp.x = view_to_col(Region.view, A[cur].x);
- tmp_n = row_to_northing(&(Region.view->cell.head), temp.y, 0.5);
- tmp_e = col_to_easting(&(Region.view->cell.head), temp.x, 0.5);
- tmp[cur].y = Rast_northing_to_row(tmp_n, &Band_cellhd);
- tmp[cur].x = Rast_easting_to_col(tmp_e, &Band_cellhd);
- }
- /* find first edge which is not horizontal */
- first = -1;
- prev = AN - 1;
- for (cur = 0; cur < AN; prev = cur++)
- if (tmp[cur].y != tmp[prev].y) {
- first = cur;
- break;
- }
- if (first < 0) {
- G_warning(_("Absurd polygon."));
- return (0);
- }
- /* copy tmp to vertex list collapsing adjacent horizontal edges */
- skip = 0;
- VN = 0;
- cur = first; /* stmt not necssary */
- do {
- if (signalflag.interrupt)
- return (0);
- if (!skip) {
- V[VN].x = tmp[cur].x;
- V[VN].y = tmp[cur].y;
- VN++;
- }
- prev = cur++;
- if (cur >= AN)
- cur = 0;
- if ((next = cur + 1) >= AN)
- next = 0;
- skip = ((tmp[prev].y == tmp[cur].y) && (tmp[next].y == tmp[cur].y));
- }
- while (cur != first);
- /* count points on the perimeter */
- np = 0;
- prev = VN - 1;
- for (cur = 0; cur < VN; prev = cur++)
- np += abs(V[prev].y - V[cur].y);
- /* allocate perimeter list */
- P = (POINT *) G_malloc(np * sizeof(POINT));
- if (!P) {
- G_warning(_("Outlined area is too large."));
- return (0);
- }
- /* store the perimeter points */
- PN = 0;
- prev = VN - 1;
- for (cur = 0; cur < VN; prev = cur++) {
- if (signalflag.interrupt)
- return (0);
- edge(V[prev].x, V[prev].y, V[cur].x, V[cur].y);
- }
- /*
- * now decide which verticies should be included
- * local extrema are excluded
- * local non-extrema are included
- * verticies of horizontal edges which are pseudo-extrema
- * are excluded.
- * one vertex of horizontal edges which are pseudo-non-extrema
- * are included.
- */
- prev = VN - 1;
- cur = 0;
- do {
- if (signalflag.interrupt)
- return (0);
- next = cur + 1;
- if (next >= VN)
- next = 0;
- if (extrema(V[prev].y, V[cur].y, V[next].y))
- skip = 1;
- else if (non_extrema(V[prev].y, V[cur].y, V[next].y))
- skip = 0;
- else {
- skip = 0;
- if (++next >= VN)
- next = 0;
- if (extrema(V[prev].y, V[cur].y, V[next].y))
- skip = 1;
- }
- if (!skip)
- edge_point(V[cur].x, V[cur].y);
- cur = next;
- prev = cur - 1;
- }
- while (cur != 0);
- /* sort the edge points by row and then by col */
- Menu_msg("Sorting...");
- qsort(P, (size_t) PN, sizeof(POINT), edge_order);
- Menu_msg("");
- return (1);
- }
|