GRASS Programmer's Manual  6.4.2(2012)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
stroke.c
Go to the documentation of this file.
1 
2 /****************************************************************************
3 *
4 * MODULE: Symbol library
5 *
6 * AUTHOR(S): Radim Blazek
7 *
8 * PURPOSE: Stroke symbol
9 *
10 * COPYRIGHT: (C) 2001 by the GRASS Development Team
11 *
12 * This program is free software under the GNU General Public
13 * License (>=v2). Read the file COPYING that comes with GRASS
14 * for details.
15 *
16 *****************************************************************************/
17 #include <stdlib.h>
18 #include <math.h>
19 #include <grass/gis.h>
20 #include <grass/symbol.h>
21 
22 #define PI M_PI
23 
24 void add_coor(SYMBCHAIN * chain, int x, int y)
25 {
26  G_debug(5, " add_coor %d, %d", x, y);
27  if (chain->scount == chain->salloc) {
28  chain->salloc += 10;
29  chain->sx = (int *)G_realloc(chain->sx, chain->salloc * sizeof(int));
30  chain->sy = (int *)G_realloc(chain->sy, chain->salloc * sizeof(int));
31  }
32  chain->sx[chain->scount] = x;
33  chain->sy[chain->scount] = y;
34  chain->scount++;
35 }
36 
37 /* draw chain
38  * s - scale
39  * ch - chain number
40  * rotation - degrees CCW from East
41  */
42 int stroke_chain(SYMBPART * part, int ch, double s, double rotation)
43 {
44  int k, l, first;
45  SYMBEL *elem;
46  SYMBCHAIN *chain;
47  double r;
48  double a1, a2, da;
49  int x, y, x0, y0;
50 
51  G_debug(5, " stroke_chain(): ch = %d", ch);
52  chain = part->chain[ch];
53 
54  G_debug(5, " element count = %d", chain->count);
55  first = 1;
56  for (k = 0; k < chain->count; k++) {
57  elem = chain->elem[k];
58  switch (elem->type) {
59  case S_LINE:
60  G_debug(5, " LINE count = %d", elem->coor.line.count);
61  for (l = 0; l < elem->coor.line.count; l++) {
62  x = s * elem->coor.line.x[l];
63  y = s * elem->coor.line.y[l];
64 
65  if (rotation != 0.0)
66  G_rotate_around_point_int(0, 0, &x, &y, rotation);
67 
68  add_coor(chain, x, y);
69  if (first) {
70  x0 = x;
71  y0 = y;
72  first = 0;
73  }
74  }
75  break;
76  case S_ARC:
77  da = 10 * PI / 180; /* later calc from size and tolerance */
78  r = elem->coor.arc.r;
79  G_debug(5, " ARC da = %f r = %f", da, r);
80 
81  /* convert to positive angles */
82  a1 = PI * elem->coor.arc.a1 / 180;
83  if (a1 < 0)
84  a1 += 2 * PI;
85  a2 = PI * elem->coor.arc.a2 / 180;
86  if (a2 < 0)
87  a2 += 2 * PI;
88 
89  if (elem->coor.arc.clock) { /* clockwise */
90  while (1) {
91  x = s * elem->coor.arc.x + s * r * cos(a1);
92  y = s * elem->coor.arc.y + s * r * sin(a1);
93 
94  if (rotation != 0.0)
95  G_rotate_around_point_int(0, 0, &x, &y, rotation);
96 
97  add_coor(chain, x, y);
98  if (first) {
99  x0 = x;
100  y0 = y;
101  first = 0;
102  }
103  if (a1 == a2)
104  break;
105  a1 -= da;
106  if (a1 < a2)
107  a1 = a2;
108  }
109 
110  }
111  else {
112  while (1) {
113  x = s * elem->coor.arc.x + s * r * cos(a1);
114  y = s * elem->coor.arc.y + s * r * sin(a1);
115 
116  if (rotation != 0.0)
117  G_rotate_around_point_int(0, 0, &x, &y, rotation);
118 
119  add_coor(chain, x, y);
120  if (first) {
121  x0 = x;
122  y0 = y;
123  first = 0;
124  }
125  if (a1 == a2)
126  break;
127  a1 += da;
128  if (a1 > a2)
129  a1 = a2;
130  }
131  }
132  break;
133  }
134  }
135  if (part->type == S_POLYGON) {
136  add_coor(chain, x0, y0); /* Close ring */
137  }
138 
139  return 0;
140 }
141 
142 /*
143  * Stroke symbol to form used for Xdriver.
144  *
145  * tolerance currently not supported
146  */
147 void S_stroke(SYMBOL * Symb, int size, double rotation, int tolerance)
148 {
149  int i, j;
150  double s;
151  SYMBPART *part;
152 
153  G_debug(3, "S_stroke(): size = %d rotation = %f tolerance = %d", size,
154  rotation, tolerance);
155 
156  /* TODO: support for tolerance */
157 
158  s = size * Symb->scale;
159 
160  for (i = 0; i < Symb->count; i++) {
161  G_debug(4, " part %d", i);
162  part = Symb->part[i];
163  switch (part->type) {
164  case S_POLYGON:
165  for (j = 0; j < part->count; j++) { /* RINGS */
166  stroke_chain(part, j, s, rotation);
167  }
168  break;
169  case S_STRING: /* string has 1 chain */
170  stroke_chain(part, 0, s, rotation);
171  break;
172  }
173  }
174 }