GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-bb27c0570b
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
13  * GRASS 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 void add_coor(SYMBCHAIN *chain, double x, double y)
25 {
26  G_debug(5, " add_coor %f, %f", x, y);
27  if (chain->scount == chain->salloc) {
28  chain->salloc += 10;
29  chain->sx =
30  (double *)G_realloc(chain->sx, chain->salloc * sizeof(double));
31  chain->sy =
32  (double *)G_realloc(chain->sy, chain->salloc * sizeof(double));
33  }
34  chain->sx[chain->scount] = x;
35  chain->sy[chain->scount] = y;
36  chain->scount++;
37 }
38 
39 /* draw chain
40  * s - scale
41  * ch - chain number
42  * rotation - degrees CCW from East
43  */
44 int stroke_chain(SYMBPART *part, int ch, double s, double rotation)
45 {
46  int k, l, first;
47  SYMBEL *elem;
48  SYMBCHAIN *chain;
49  double r;
50  double a1, a2, da;
51  double x, y, x0, y0;
52 
53  G_debug(5, " stroke_chain(): ch = %d", ch);
54  chain = part->chain[ch];
55 
56  G_debug(5, " element count = %d", chain->count);
57  first = 1;
58  for (k = 0; k < chain->count; k++) {
59  elem = chain->elem[k];
60  switch (elem->type) {
61  case S_LINE:
62  G_debug(5, " LINE count = %d", elem->coor.line.count);
63  for (l = 0; l < elem->coor.line.count; l++) {
64  x = s * elem->coor.line.x[l];
65  y = s * elem->coor.line.y[l];
66 
67  if (rotation != 0.0)
68  G_rotate_around_point(0, 0, &x, &y, rotation);
69 
70  add_coor(chain, x, y);
71  if (first) {
72  x0 = x;
73  y0 = y;
74  first = 0;
75  }
76  }
77  break;
78  case S_ARC:
79  if (s >= 50)
80  da = 1 * PI / 180; /* later calc from size and tolerance */
81  else
82  da = 10 * PI / 180;
83 
84  r = elem->coor.arc.r;
85  G_debug(5, " ARC da = %f r = %f", da, r);
86 
87  /* convert to positive angles */
88  a1 = PI * elem->coor.arc.a1 / 180;
89  if (a1 < 0)
90  a1 += 2 * PI;
91  a2 = PI * elem->coor.arc.a2 / 180;
92  if (a2 < 0)
93  a2 += 2 * PI;
94 
95  if (elem->coor.arc.clock) { /* clockwise */
96  while (1) {
97  x = s * elem->coor.arc.x + s * r * cos(a1);
98  y = s * elem->coor.arc.y + s * r * sin(a1);
99 
100  if (rotation != 0.0)
101  G_rotate_around_point(0, 0, &x, &y, rotation);
102 
103  add_coor(chain, x, y);
104  if (first) {
105  x0 = x;
106  y0 = y;
107  first = 0;
108  }
109  if (a1 == a2)
110  break;
111  a1 -= da;
112  if (a1 < a2)
113  a1 = a2;
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", size,
165  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 G_realloc(p, n)
Definition: defs/gis.h:96
void G_rotate_around_point(double, double, double *, double *, double)
Rotate point (double version)
Definition: rotate.c:33
int G_debug(int, const char *,...) __attribute__((format(printf
double l
Definition: r_raster.c:39
double r
Definition: r_raster.c:39
void add_coor(SYMBCHAIN *chain, double x, double y)
Definition: stroke.c:24
void S_stroke(SYMBOL *Symb, double size, double rotation, int tolerance)
Stroke symbol to form used for Xdriver.
Definition: stroke.c:158
#define PI
Definition: stroke.c:22
int stroke_chain(SYMBPART *part, int ch, double s, double rotation)
Definition: stroke.c:44
int count
Definition: symbol.h:45
double * sy
Definition: symbol.h:48
int scount
Definition: symbol.h:47
SYMBEL ** elem
Definition: symbol.h:46
int salloc
Definition: symbol.h:47
double * sx
Definition: symbol.h:48
Definition: symbol.h:29
struct SYMBEL::@6::@8 arc
int type
Definition: symbol.h:30
union SYMBEL::@6 coor
struct SYMBEL::@6::@7 line
Definition: symbol.h:60
double scale
Definition: symbol.h:61
int count
Definition: symbol.h:65
SYMBPART ** part
Definition: symbol.h:66
SYMBCHAIN ** chain
Definition: symbol.h:57
int type
Definition: symbol.h:53
int count
Definition: symbol.h:56
#define S_STRING
Definition: symbol.h:15
#define S_LINE
Definition: symbol.h:11
#define S_POLYGON
Definition: symbol.h:16
#define S_ARC
Definition: symbol.h:12
#define x