GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
plus_area.c
Go to the documentation of this file.
1 
17 #include <stdlib.h>
18 #include <grass/Vect.h>
19 #include <grass/glocale.h>
20 
48 int
49 dig_build_area_with_line(struct Plus_head *plus, plus_t first_line, int side,
50  plus_t ** lines)
51 {
52  register int i;
53  int prev_line, next_line;
54  static plus_t *array;
55  char *p;
56  static int array_size; /* 0 on startup */
57  int n_lines;
58  P_LINE *Line;
59  int node;
60  const char *dstr;
61  int debug_level;
62 
63  dstr = G__getenv("DEBUG");
64 
65  if (dstr != NULL)
66  debug_level = atoi(dstr);
67  else
68  debug_level = 0;
69 
70  G_debug(3, "dig_build_area_with_line(): first_line = %d, side = %d",
71  first_line, side);
72 
73  /* First check if line is not degenerated (degenerated lines have angle -9)
74  * Following degenerated lines are skip by dig_angle_next_line() */
75  Line = plus->Line[first_line];
76  node = Line->N1; /* to check one is enough, because if degenerated N1 == N2 */
77  if (dig_node_line_angle(plus, node, first_line) == -9.) {
78  G_debug(3, "First line degenerated");
79  return (0);
80  }
81 
82  if (array_size == 0) { /* first time */
83  array_size = 1000;
84  array = (plus_t *) dig__falloc(array_size, sizeof(plus_t));
85  if (array == NULL)
86  return (dig_out_of_memory());
87  }
88 
89  if (side == GV_LEFT) {
90  first_line = -first_line; /* start at node1, reverse direction */
91  }
92  array[0] = first_line;
93  prev_line = -first_line; /* start at node2 for direct and node1 for
94  reverse direction */
95  /* angle of first line */
96  n_lines = 1;
97  while (1) {
98  next_line =
99  dig_angle_next_line(plus, prev_line, GV_RIGHT, GV_BOUNDARY);
100  G_debug(3, "next_line = %d", next_line);
101 
102  if (next_line == 0)
103  return (-1); /* Not found */
104 
105  /* Check if adjacent lines do not have the same angle */
106  if (!dig_node_angle_check(plus, next_line, GV_BOUNDARY)) {
107  G_debug(3,
108  "Cannot build area, a neighbour of the line %d has the same angle at the node",
109  next_line);
110  return 0;
111  }
112 
113  /* I. Area closed. This also handles the problem w/ 1 single area line */
114  if (first_line == next_line) {
115  /* GOT ONE! fill area struct and return */
116  G_debug(3, "Got one! :");
117 
118  /* avoid loop when not debugging */
119  if (debug_level > 2) {
120  for (i = 0; i < n_lines; i++) {
121  G_debug(3, " area line (%d) = %d", i, array[i]);
122  }
123  }
124 
125  *lines = array;
126  return (n_lines);
127  }
128 
129  /* II. Note this is a dead end */
130  /* ( if prev_line != -first_line so it goes after the previous test) ? */
131  if (prev_line == next_line) {
132  G_debug(3, "Dead_end:");
133  return (0); /* dead end */
134  }
135 
136  /* III. Unclosed ?, I would say started from free end */
137  for (i = 0; i < n_lines; i++)
138  if (abs(next_line) == abs(array[i])) {
139  G_debug(3, "Unclosed area:");
140  return (0); /* ran into a different area */
141  }
142 
143  /* otherwise keep going */
144  if (n_lines >= array_size) {
145  p = dig__frealloc(array, array_size + 100, sizeof(plus_t),
146  array_size);
147  if (p == NULL)
148  return (dig_out_of_memory());
149  array = (plus_t *) p;
150  array_size += 100;
151  }
152  array[n_lines++] = next_line;
153  prev_line = -next_line;
154  }
155 
156  return 0;
157 }
158 
173 int dig_add_area(struct Plus_head *plus, int n_lines, plus_t * lines)
174 {
175  register int i;
176  register int area, line;
177  P_AREA *Area;
178  P_LINE *Line;
179  BOUND_BOX box, abox;
180 
181  G_debug(3, "dig_add_area():");
182  /* First look if we have space in array of pointers to areas
183  * and reallocate if necessary */
184  if (plus->n_areas >= plus->alloc_areas) { /* array is full */
185  if (dig_alloc_areas(plus, 1000) == -1)
186  return -1;
187  }
188 
189  /* allocate area structure */
190  area = plus->n_areas + 1;
191  G_debug(3, " new area = %d", area);
192  Area = dig_alloc_area();
193  if (Area == NULL)
194  return -1;
195 
196  if (dig_area_alloc_line(Area, n_lines) == -1)
197  return -1;
198 
199  for (i = 0; i < n_lines; i++) {
200  line = lines[i];
201  Area->lines[i] = line;
202  Line = plus->Line[abs(line)];
203  if (plus->do_uplist)
204  dig_line_add_updated(plus, abs(line));
205  if (line < 0) { /* revers direction -> area on left */
206  if (Line->left != 0) {
207  G_warning(_("Line %d already has area/isle %d to left"), line,
208  Line->left);
209  return -1;
210  }
211 
212  G_debug(3, " Line %d left set to %d.", line, area);
213  Line->left = area;
214  }
215  else {
216  if (Line->right != 0) {
217  G_warning(_("Line %d already has area/isle %d to right"),
218  line, Line->right);
219  return -1;
220  }
221 
222  G_debug(3, " Line %d right set to %d.", line, area);
223  Line->right = area;
224  }
225  dig_line_get_box(plus, abs(line), &box);
226  if (i == 0)
227  dig_box_copy(&abox, &box);
228  else
229  dig_box_extend(&abox, &box);
230  }
231  Area->n_lines = n_lines;
232  Area->centroid = 0;
233 
234  plus->Area[area] = Area;
235  dig_area_set_box(plus, area, &abox);
236 
237  dig_spidx_add_area(plus, area, &abox);
238 
239  plus->n_areas++;
240 
241  return (area);
242 }
243 
253 int dig_area_add_isle(struct Plus_head *plus, int area, int isle)
254 {
255  int i;
256  P_AREA *Area;
257 
258  G_debug(3, "dig_area_add_isle(): area = %d isle = %d", area, isle);
259 
260  Area = plus->Area[area];
261  if (Area == NULL)
262  G_fatal_error("Attempt to add isle to dead area");
263 
264  for (i = 0; i < Area->n_isles; i++) {
265  if (Area->isles[i] == isle) { /* Already exist */
266  G_debug(3, "isle already registered in area");
267  return 0;
268  }
269  }
270 
271  if (Area->alloc_isles <= Area->n_isles) /* array is full */
272  dig_area_alloc_isle(Area, 1);
273 
274  Area->isles[Area->n_isles] = isle;
275  Area->n_isles++;
276  G_debug(3, " -> n_isles = %d", Area->n_isles);
277 
278  return 0;
279 }
280 
290 int dig_area_del_isle(struct Plus_head *plus, int area, int isle)
291 {
292  int i, mv;
293  P_AREA *Area;
294 
295  G_debug(3, "dig_area_del_isle(): area = %d isle = %d", area, isle);
296 
297  Area = plus->Area[area];
298  if (Area == NULL)
299  G_fatal_error(_("Attempt to delete isle from dead area"));
300 
301  mv = 0;
302  for (i = 0; i < Area->n_isles; i++) {
303  if (mv) {
304  Area->isles[i - 1] = Area->isles[i];
305  }
306  else {
307  if (Area->isles[i] == isle)
308  mv = 1;
309  }
310  }
311 
312  if (mv) {
313  Area->n_isles--;
314  }
315  else {
316  G_fatal_error(_("Attempt to delete not registered isle %d from area %d"),
317  isle, area);
318  }
319 
320  return 0;
321 }
322 
341 int dig_del_area(struct Plus_head *plus, int area)
342 {
343  int i, line;
344 
345  /* int isle, area_out; */
346  P_AREA *Area;
347  P_LINE *Line;
348  P_ISLE *Isle;
349 
350  G_debug(3, "dig_del_area() area = %d", area);
351  Area = plus->Area[area];
352 
353  if (Area == NULL) {
354  G_warning(_("Attempt to delete dead area"));
355  return 0;
356  }
357 
358  dig_spidx_del_area(plus, area);
359 
360  /* Set area for all lines to 0 */
361  /* isle = 0; */
362  for (i = 0; i < Area->n_lines; i++) {
363  line = Area->lines[i]; /* >0 = clockwise -> right, <0 = counterclockwise ->left */
364  Line = plus->Line[abs(line)];
365  if (plus->do_uplist)
366  dig_line_add_updated(plus, abs(line));
367  if (line > 0) {
368  G_debug(3, " Set line %d right side to 0", line);
369  Line->right = 0;
370  }
371  else {
372  G_debug(3, " Set line %d left side to 0", line);
373  Line->left = 0;
374  }
375 
376  /* Find the isle this area is part of (used late below) */
377  /*
378  if ( line > 0 ) {
379  if ( Line->left < 0 ) isle = Line->left;
380  } else {
381  if ( Line->right < 0 ) isle = Line->right;
382  }
383  */
384  }
385 
386  /* Unset area information of centroid */
387  /* TODO: duplicate centroids have also area information ->
388  * 1) do not save such info
389  * 2) find all by box and reset info */
390  line = Area->centroid;
391  if (line > 0) {
392  Line = plus->Line[line];
393  if (!Line) {
394  G_warning(_("Dead centroid %d registered for area (bug in the vector library)"),
395  line);
396  }
397  else {
398  Line->left = 0;
399  if (plus->do_uplist)
400  dig_line_add_updated(plus, line);
401  }
402  }
403 
404  /* Find the area this area is within */
405  /*
406  area_out = 0;
407  if ( isle > 0 ) {
408  Isle = plus->Isle[abs(isle)];
409  area_out = Isle->area;
410  }
411  */
412 
413  /* Reset information about area outside for isles within this area */
414  G_debug(3, " n_isles = %d", Area->n_isles);
415  for (i = 0; i < Area->n_isles; i++) {
416  Isle = plus->Isle[Area->isles[i]];
417  if (Isle == NULL) {
418  G_fatal_error(_("Attempt to delete area %d info from dead isle %d"),
419  area, Area->isles[i]);
420  }
421  else {
422  /* Isle->area = area_out; */
423  Isle->area = 0;
424  }
425  }
426 
427  /* TODO: free structures */
428  plus->Area[area] = NULL;
429  return 1;
430 }
431 
441 int dig_area_set_box(struct Plus_head *plus, plus_t area, BOUND_BOX * Box)
442 {
443  P_AREA *Area;
444 
445  Area = plus->Area[area];
446 
447  Area->N = Box->N;
448  Area->S = Box->S;
449  Area->E = Box->E;
450  Area->W = Box->W;
451  Area->T = Box->T;
452  Area->B = Box->B;
453 
454  return (1);
455 }
456 
457 
473 int
474 dig_angle_next_line(struct Plus_head *plus, plus_t current_line, int side,
475  int type)
476 {
477  int i, next;
478  int current;
479  int line;
480  plus_t node;
481  P_NODE *Node;
482  P_LINE *Line;
483  const char *dstr;
484  int debug_level;
485 
486  dstr = G__getenv("DEBUG");
487 
488  if (dstr != NULL)
489  debug_level = atoi(dstr);
490  else
491  debug_level = 0;
492 
493  G_debug(3, "dig__angle_next_line: line = %d, side = %d, type = %d",
494  current_line, side, type);
495 
496  Line = plus->Line[abs(current_line)];
497  if (current_line > 0)
498  node = Line->N1;
499  else
500  node = Line->N2;
501 
502  G_debug(3, " node = %d", node);
503 
504  Node = plus->Node[node];
505  G_debug(3, " n_lines = %d", Node->n_lines);
506  /* avoid loop when not debugging */
507  if (debug_level > 2) {
508  for (i = 0; i < Node->n_lines; i++) {
509  G_debug(3, " i = %d line = %d angle = %f", i, Node->lines[i],
510  Node->angles[i]);
511  }
512  }
513 
514  /* first find index for that line */
515  next = -1;
516  for (current = 0; current < Node->n_lines; current++) {
517  if (Node->lines[current] == current_line)
518  next = current;
519  }
520  if (next == -1)
521  return 0; /* not found */
522 
523  G_debug(3, " current position = %d", next);
524  while (1) {
525  if (side == GV_RIGHT) { /* go up (greater angle) */
526  if (next == Node->n_lines - 1)
527  next = 0;
528  else
529  next++;
530  }
531  else { /* go down (smaller angle) */
532  if (next == 0)
533  next = Node->n_lines - 1;
534  else
535  next--;
536  }
537  G_debug(3, " next = %d line = %d angle = %f", next,
538  Node->lines[next], Node->angles[next]);
539 
540  if (Node->angles[next] == -9.) { /* skip points and degenerated */
541  G_debug(3, " point/degenerated -> skip");
542  if (Node->lines[next] == current_line)
543  break; /* Yes, that may happen if input line is degenerated and isolated and this breaks loop */
544  else
545  continue;
546  }
547 
548  line = abs(Node->lines[next]);
549  Line = plus->Line[line];
550 
551  if (Line->type & type) { /* line found */
552  G_debug(3, " this one");
553  return (Node->lines[next]);
554  }
555 
556  /* input line reached, this must be last, because current_line may be correct return value (dangle) */
557  if (Node->lines[next] == current_line)
558  break;
559  }
560  G_debug(3, " Line NOT found at node %d", (int)node);
561  return 0;
562 }
563 
578 int dig_node_angle_check(struct Plus_head *plus, plus_t line, int type)
579 {
580  int next, prev;
581  float angle1, angle2;
582  plus_t node;
583  P_LINE *Line;
584 
585  G_debug(3, "dig_node_angle_check: line = %d, type = %d", line, type);
586 
587  Line = plus->Line[abs(line)];
588 
589  if (line > 0)
590  node = Line->N1;
591  else
592  node = Line->N2;
593 
594  angle1 = dig_node_line_angle(plus, node, line);
595 
596  /* Next */
597  next = dig_angle_next_line(plus, line, GV_RIGHT, type);
598  angle2 = dig_node_line_angle(plus, node, next);
599  if (angle1 == angle2) {
600  G_debug(3,
601  " The line to the right has the same angle: node = %d, line = %d",
602  node, next);
603  return 0;
604  }
605 
606  /* Previous */
607  prev = dig_angle_next_line(plus, line, GV_LEFT, type);
608  angle2 = dig_node_line_angle(plus, node, prev);
609  if (angle1 == angle2) {
610  G_debug(3,
611  " The line to the left has the same angle: node = %d, line = %d",
612  node, next);
613  return 0;
614  }
615 
616  return 1; /* OK */
617 }
618 
634 int dig_add_isle(struct Plus_head *plus, int n_lines, plus_t * lines)
635 {
636  register int i;
637  register int isle, line;
638  P_ISLE *Isle;
639  P_LINE *Line;
640  BOUND_BOX box, abox;
641 
642  G_debug(3, "dig_add_isle():");
643  /* First look if we have space in array of pointers to isles
644  * and reallocate if necessary */
645  if (plus->n_isles >= plus->alloc_isles) { /* array is full */
646  if (dig_alloc_isles(plus, 1000) == -1)
647  return -1;
648  }
649 
650  /* allocate isle structure */
651  isle = plus->n_isles + 1;
652  Isle = dig_alloc_isle();
653  if (Isle == NULL)
654  return -1;
655 
656  if ((dig_isle_alloc_line(Isle, n_lines)) == -1)
657  return -1;
658 
659  Isle->area = 0;
660 
661  Isle->N = 0;
662  Isle->S = 0;
663  Isle->E = 0;
664  Isle->W = 0;
665 
666  for (i = 0; i < n_lines; i++) {
667  line = lines[i];
668  G_debug(3, " i = %d line = %d", i, line);
669  Isle->lines[i] = line;
670  Line = plus->Line[abs(line)];
671  if (plus->do_uplist)
672  dig_line_add_updated(plus, abs(line));
673  if (line < 0) { /* revers direction -> isle on left */
674  if (Line->left != 0) {
675  G_warning(_("Line %d already has area/isle %d to left"), line,
676  Line->left);
677  return -1;
678  }
679  Line->left = -isle;
680  }
681  else {
682  if (Line->right != 0) {
683  G_warning(_("Line %d already has area/isle %d to left"), line,
684  Line->right);
685  return -1;
686  }
687 
688  Line->right = -isle;
689  }
690  dig_line_get_box(plus, abs(line), &box);
691  if (i == 0)
692  dig_box_copy(&abox, &box);
693  else
694  dig_box_extend(&abox, &box);
695  }
696 
697  Isle->n_lines = n_lines;
698 
699  plus->Isle[isle] = Isle;
700 
701  dig_isle_set_box(plus, isle, &abox);
702 
703  dig_spidx_add_isle(plus, isle, &abox);
704 
705  plus->n_isles++;
706 
707  return (isle);
708 }
709 
710 
720 int dig_isle_set_box(struct Plus_head *plus, plus_t isle, BOUND_BOX * Box)
721 {
722  P_ISLE *Isle;
723 
724  Isle = plus->Isle[isle];
725 
726  Isle->N = Box->N;
727  Isle->S = Box->S;
728  Isle->E = Box->E;
729  Isle->W = Box->W;
730  Isle->T = Box->T;
731  Isle->B = Box->B;
732 
733  return (1);
734 }
735 
746 int dig_del_isle(struct Plus_head *plus, int isle)
747 {
748  int i, line;
749  P_LINE *Line;
750  P_ISLE *Isle;
751 
752  G_debug(3, "dig_del_isle() isle = %d", isle);
753  Isle = plus->Isle[isle];
754 
755  dig_spidx_del_isle(plus, isle);
756 
757  /* Set area for all lines to 0 */
758  for (i = 0; i < Isle->n_lines; i++) {
759  line = Isle->lines[i]; /* >0 = clockwise -> right, <0 = counterclockwise ->left */
760  Line = plus->Line[abs(line)];
761  if (plus->do_uplist)
762  dig_line_add_updated(plus, abs(line));
763  if (line > 0)
764  Line->right = 0;
765  else
766  Line->left = 0;
767  }
768 
769  /* Delete reference from area it is within */
770  G_debug(3, " area outside isle = %d", Isle->area);
771  if (Isle->area > 0) {
772  if (plus->Area[Isle->area] == NULL) {
773  G_fatal_error(_("Attempt to delete isle %d info from dead area %d"),
774  isle, Isle->area);
775  }
776  else {
777  dig_area_del_isle(plus, Isle->area, isle);
778  }
779  }
780 
781  /* TODO: free structures */
782 
783  plus->Isle[isle] = NULL;
784 
785  return 1;
786 }
int dig_area_alloc_isle(P_AREA *area, int add)
Definition: struct_alloc.c:325
void * dig__frealloc(void *oldptr, int nelem, int elsize, int oldnelem)
Definition: allocation.c:133
char * G__getenv(const char *name)
Get environment variable.
Definition: env.c:312
int dig_del_isle(struct Plus_head *plus, int isle)
Delete island from Plus_head structure.
Definition: plus_area.c:746
float Box[8][3]
Vertices for box.
Definition: gsd_objs.c:1420
int debug_level
Definition: core.py:69
float dig_node_line_angle(struct Plus_head *plus, int nodeid, int lineid)
Return line angle.
Definition: plus_node.c:202
int dig_del_area(struct Plus_head *plus, int area)
Delete area from Plus_head structure.
Definition: plus_area.c:341
Definition: index.h:56
void * dig__falloc(int nelem, int elsize)
Definition: allocation.c:118
int dig_angle_next_line(struct Plus_head *plus, plus_t current_line, int side, int type)
Find number line of next angle to follow an line.
Definition: plus_area.c:474
int dig_alloc_areas(struct Plus_head *Plus, int add)
Definition: struct_alloc.c:149
int dig_box_extend(BOUND_BOX *A, BOUND_BOX *B)
Definition: diglib/box.c:86
tuple box
surface = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _(&quot;Follow source viewpoint&quot;)) pageSizer...
Definition: tools.py:1527
int dig_spidx_add_area(struct Plus_head *Plus, int area, BOUND_BOX *box)
Add new area to spatial index.
Definition: spindex.c:174
int dig_out_of_memory()
Definition: struct_alloc.c:369
int dig_line_get_box(struct Plus_head *plus, plus_t line, BOUND_BOX *Box)
Get line bounding box saved in topo.
Definition: plus_line.c:343
int dig_spidx_add_isle(struct Plus_head *Plus, int isle, BOUND_BOX *box)
Add new island to spatial index.
Definition: spindex.c:201
int dig_area_add_isle(struct Plus_head *plus, int area, int isle)
Add isle to area if does not exist yet.
Definition: plus_area.c:253
int dig_build_area_with_line(struct Plus_head *plus, plus_t first_line, int side, plus_t **lines)
Build topo for area from lines.
Definition: plus_area.c:49
int dig_spidx_del_area(struct Plus_head *Plus, int area)
Delete area from spatial index.
Definition: spindex.c:303
P_ISLE * dig_alloc_isle()
Definition: struct_alloc.c:211
int dig_area_alloc_line(P_AREA *area, int add)
Definition: struct_alloc.c:303
int dig_alloc_isles(struct Plus_head *Plus, int add)
Definition: struct_alloc.c:171
int dig_isle_set_box(struct Plus_head *plus, plus_t isle, BOUND_BOX *Box)
Set isle bounding box.
Definition: plus_area.c:720
int dig_isle_alloc_line(P_ISLE *isle, int add)
Definition: struct_alloc.c:348
int dig_spidx_del_isle(struct Plus_head *Plus, int isle)
Delete isle from spatial index.
Definition: spindex.c:342
int dig_box_copy(BOUND_BOX *A, BOUND_BOX *B)
Definition: diglib/box.c:69
P_AREA * dig_alloc_area()
Definition: struct_alloc.c:189
return NULL
Definition: dbfopen.c:1394
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: gis/debug.c:51
int dig_node_angle_check(struct Plus_head *plus, plus_t line, int type)
Checks if angles of adjacent lines differ.
Definition: plus_area.c:578
void dig_line_add_updated(struct Plus_head *Plus, int line)
Add new line to updated.
int dig_area_set_box(struct Plus_head *plus, plus_t area, BOUND_BOX *Box)
Set area bounding box.
Definition: plus_area.c:441
int G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
int dig_add_isle(struct Plus_head *plus, int n_lines, plus_t *lines)
Allocate space for new island and create boundary info from array.
Definition: plus_area.c:634
int dig_add_area(struct Plus_head *plus, int n_lines, plus_t *lines)
Allocate space for new area and create boundary info from array.
Definition: plus_area.c:173
int dig_area_del_isle(struct Plus_head *plus, int area, int isle)
Delete isle from area.
Definition: plus_area.c:290