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