GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-8cbe8fef7c
vector/vedit/render.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/vedit/render.c
3 
4  \brief Vedit library - render vector features (used by wxGUI digitizer)
5 
6  (C) 2010-2011 by the GRASS Development Team
7 
8  This program is free software under the GNU General Public License
9  (>=v2). Read the file COPYING that comes with GRASS for details.
10 
11  \author Martin Landa <landa.martin gmail.com>
12  */
13 
14 #include <math.h>
15 
16 #include <grass/vedit.h>
17 
18 static struct _region {
19  double center_easting;
20  double center_northing;
21  double map_west;
22  double map_north;
23  int map_width;
24  int map_height;
25  double map_res;
26 } region;
27 
28 static struct _state {
29  int nitems_alloc;
30 
31  int type;
32  struct line_pnts *Points;
33 } state;
34 
35 static struct robject *draw_line(struct Map_info *, int, int);
36 static struct robject *draw_line_vertices(void);
37 static void draw_line_nodes(struct Map_info *, int, int, struct robject_list *);
38 static int draw_line_dir(struct robject_list *, int);
39 static void list_append(struct robject_list *, struct robject *);
40 static struct robject *robj_alloc(int, int);
41 static void robj_points(struct robject *, const struct line_pnts *);
42 static double dist_in_px(double);
43 static void en_to_xy(double, double, int *, int *);
44 static void draw_arrow(int, int, int, int, double, int, int,
45  struct robject_list *);
46 static void draw_area(struct Map_info *, int, struct robject_list *);
47 
48 /*!
49  \brief Render vector features into list
50 
51  \param Map pointer to Map_info structure
52  \param box bounding box of region to be rendered
53  \param draw_flag types of objects to be rendered (see vedit.h)
54  \param center_easing, center_northing, map_width, map_height, map_res values
55  used for conversion en->xy
56 
57  \return pointer to robject_list structure
58  */
60  struct bound_box *box, int draw_flag,
61  double center_easting,
62  double center_northing, int map_width,
63  int map_height, double map_res)
64 {
65  int i, nfeat, fid;
66  struct boxlist *list;
67  struct robject_list *list_obj;
68  struct robject *robj;
69 
70  /* define region */
71  region.center_easting = center_easting;
72  region.center_northing = center_northing;
73  region.map_width = map_width;
74  region.map_height = map_height;
75  region.map_res = map_res;
76  region.map_west = center_easting - (map_width / 2.) * map_res;
77  region.map_north = center_northing + (map_height / 2.) * map_res;
78 
80  list_obj = NULL;
81  state.nitems_alloc = 1000;
82 
83  list_obj = (struct robject_list *)G_malloc(sizeof(struct robject_list));
84  list_obj->nitems = 0;
85  list_obj->item = (struct robject **)G_malloc(state.nitems_alloc *
86  sizeof(struct robject *));
87 
88  /* area */
89  if (draw_flag & DRAW_AREA) {
90  nfeat = Vect_select_areas_by_box(Map, box, list);
91  for (i = 0; i < nfeat; i++) {
92  fid = list->id[i];
93  draw_area(Map, fid, list_obj);
94  }
95  }
96 
97  /* draw lines inside of current display region */
98  nfeat = Vect_select_lines_by_box(Map, box, GV_POINTS | GV_LINES, /* fixme */
99  list);
100  G_debug(1, "Vedit_render_map(): region: w=%f, e=%f, s=%f, n=%f nlines=%d",
101  box->W, box->E, box->S, box->N, nfeat);
102 
103  /* features */
104  for (i = 0; i < list->n_values; i++) {
105  fid = list->id[i];
106  robj = draw_line(Map, fid, draw_flag);
107  if (!robj)
108  continue;
109  list_append(list_obj, robj);
110 
111  if (state.type & GV_LINES) {
112  /* vertices */
113  if (draw_flag & DRAW_VERTEX) {
114  robj = draw_line_vertices();
115  robj->fid = fid;
116  if (robj)
117  list_append(list_obj, robj);
118  }
119  /* nodes */
120  if (draw_flag & (DRAW_NODEONE | DRAW_NODETWO)) {
121  draw_line_nodes(Map, fid, draw_flag, list_obj);
122  }
123  /* direction */
124  if (draw_flag & DRAW_DIRECTION) {
125  draw_line_dir(list_obj, fid);
126  }
127  }
128  }
129 
130  list_obj->item = (struct robject **)G_realloc(
131  list_obj->item, list_obj->nitems * sizeof(struct robject *));
132 
133  G_debug(1, "Vedit_render_map(): -> nitems = %d", list_obj->nitems);
134 
136 
137  return list_obj;
138 }
139 
140 /*!
141  \brief Draw one feature
142  */
143 struct robject *draw_line(struct Map_info *Map, int line, int draw_flag)
144 {
145  int draw;
146  struct robject *obj;
147 
148  if (!state.Points)
149  state.Points = Vect_new_line_struct();
150 
151  if (!Vect_line_alive(Map, line))
152  return NULL;
153 
154  state.type = Vect_read_line(Map, state.Points, NULL, line);
155 
156  obj = (struct robject *)G_malloc(sizeof(struct robject));
157  obj->fid = line;
158  draw = FALSE;
159  if (state.type & GV_LINES) {
160  if (state.type == GV_LINE) {
161  obj->type = TYPE_LINE;
162  draw = draw_flag & DRAW_LINE;
163  }
164  else if (state.type == GV_BOUNDARY) {
165  int left, right;
166 
167  Vect_get_line_areas(Map, line, &left, &right);
168  if (left == 0 && right == 0) {
169  obj->type = TYPE_BOUNDARYNO;
170  draw = draw_flag & DRAW_BOUNDARYNO;
171  }
172  else if (left > 0 && right > 0) {
173  obj->type = TYPE_BOUNDARYTWO;
174  draw = draw_flag & DRAW_BOUNDARYTWO;
175  }
176  else {
177  obj->type = TYPE_BOUNDARYONE;
178  draw = draw_flag & DRAW_BOUNDARYONE;
179  }
180  }
181  }
182  else if (state.type & GV_POINTS) {
183  if (state.type == GV_POINT) {
184  obj->type = TYPE_POINT;
185  draw = draw_flag & DRAW_POINT;
186  }
187  else if (state.type == GV_CENTROID) {
188  int cret = Vect_get_centroid_area(Map, line);
189 
190  if (cret > 0) { /* -> area */
191  obj->type = TYPE_CENTROIDIN;
192  draw = draw_flag & DRAW_CENTROIDIN;
193  }
194  else if (cret == 0) {
195  obj->type = TYPE_CENTROIDOUT;
196  draw = draw_flag & DRAW_CENTROIDOUT;
197  }
198  else {
199  obj->type = TYPE_CENTROIDDUP;
200  draw = draw_flag & DRAW_CENTROIDDUP;
201  }
202  }
203  }
204  G_debug(3, " draw_line(): type=%d rtype=%d npoints=%d draw=%d", state.type,
205  obj->type, state.Points->n_points, draw);
206 
207  if (!draw)
208  return NULL;
209 
210  obj->npoints = state.Points->n_points;
211  obj->point =
212  (struct rpoint *)G_malloc(obj->npoints * sizeof(struct rpoint));
213  robj_points(obj, state.Points);
214 
215  return obj;
216 }
217 
218 /*!
219  \brief Convert geographic coordinates to the screen
220  */
221 void en_to_xy(double east, double north, int *x, int *y)
222 {
223  double n, w;
224 
225  w = region.center_easting - (region.map_width / 2) * region.map_res;
226  n = region.center_northing + (region.map_height / 2) * region.map_res;
227 
228  if (x)
229  *x = (east - w) / region.map_res;
230  if (y)
231  *y = (n - north) / region.map_res;
232 
233  return;
234 }
235 
236 /*!
237  \brief Draw line nodes
238  */
239 void draw_line_nodes(struct Map_info *Map, int line, int draw_flag,
240  struct robject_list *list)
241 {
242  unsigned int i;
243  int type, nodes[2];
244  int x, y;
245  double east, north;
246  struct robject *robj;
247 
248  if (Vect_get_line_type(Map, line) & GV_POINTS)
249  return;
250 
251  Vect_get_line_nodes(Map, line, &(nodes[0]), &(nodes[1]));
252 
253  for (i = 0; i < sizeof(nodes) / sizeof(int); i++) {
254  type = 0;
255  if (Vect_get_node_n_lines(Map, nodes[i]) == 1) {
256  if (draw_flag & DRAW_NODEONE) {
257  type = TYPE_NODEONE;
258  }
259  }
260  else {
261  if (draw_flag & DRAW_NODETWO) {
262  type = TYPE_NODETWO;
263  }
264  }
265 
266  if (type == 0)
267  continue;
268 
269  Vect_get_node_coor(Map, nodes[i], &east, &north, NULL);
270 
271  robj = robj_alloc(type, 1);
272  en_to_xy(east, north, &x, &y);
273  robj->fid = line;
274  robj->point->x = x;
275  robj->point->y = y;
276 
277  list_append(list, robj);
278  }
279 }
280 
281 /*!
282  \brief Append object to the list
283  */
284 void list_append(struct robject_list *list, struct robject *obj)
285 {
286  if (list->nitems >= state.nitems_alloc) {
287  state.nitems_alloc += 1000;
288  list->item = (struct robject **)G_realloc(
289  list->item, state.nitems_alloc * sizeof(struct robject *));
290  }
291  list->item[list->nitems++] = obj;
292 }
293 
294 /*!
295  \brief Allocate robject
296  */
297 struct robject *robj_alloc(int type, int npoints)
298 {
299  struct robject *robj;
300 
301  robj = (struct robject *)G_malloc(sizeof(struct robject));
302  robj->type = type;
303  robj->npoints = npoints;
304  robj->point = (struct rpoint *)G_malloc(npoints * sizeof(struct rpoint));
305 
306  return robj;
307 }
308 
309 /*!
310  \brief Draw line vertices
311  */
312 struct robject *draw_line_vertices(void)
313 {
314  int i;
315  int x, y;
316  struct robject *robj;
317 
318  robj =
319  robj_alloc(TYPE_VERTEX, state.Points->n_points - 2); /* ignore nodes */
320 
321  for (i = 1; i < state.Points->n_points - 1; i++) {
322  en_to_xy(state.Points->x[i], state.Points->y[i], &x, &y);
323  robj->point[i - 1].x = x;
324  robj->point[i - 1].y = y;
325  }
326 
327  return robj;
328 }
329 
330 /*!
331  \brief Draw line dirs
332  */
333 int draw_line_dir(struct robject_list *list, int line)
334 {
335  int narrows;
336  int size; /* arrow length in pixels */
337  int limit; /* segment length limit for drawing symbol (in pixels) */
338  double dist, angle, pos;
339  double e, n;
340  int x0, y0, x1, y1;
341 
342  narrows = 0;
343  size = 5;
344  limit = 5; /* 5px for line segment */
345 
346  dist = Vect_line_length(state.Points);
347  G_debug(5, " draw_line_dir() line=%d", line);
348 
349  if (dist_in_px(dist) >= limit) {
350  while (1) {
351  pos = (narrows + 1) * 8 * limit * region.map_res;
352 
353  if (Vect_point_on_line(state.Points, pos, &e, &n, NULL, NULL,
354  NULL) < 1) {
355  break;
356  }
357 
358  en_to_xy(e, n, &x0, &y0);
359 
360  if (Vect_point_on_line(state.Points,
361  pos - 3 * size * region.map_res, &e, &n,
362  NULL, &angle, NULL) < 1) {
363  break;
364  }
365 
366  en_to_xy(e, n, &x1, &y1);
367 
368  draw_arrow(x0, y0, x1, y1, angle, size, line, list);
369 
370  if (narrows > 1e2) /* low resolution, break */
371  break;
372 
373  narrows++;
374  }
375 
376  /* draw at least one arrow in the middle of line */
377  if (narrows < 1) {
378  dist /= 2.;
379  if (Vect_point_on_line(state.Points, dist, &e, &n, NULL, NULL,
380  NULL) > 0) {
381 
382  en_to_xy(e, n, &x0, &y0);
383 
384  if (Vect_point_on_line(state.Points,
385  dist - 3 * size * region.map_res, &e, &n,
386  NULL, &angle, NULL) > 0) {
387 
388  en_to_xy(e, n, &x1, &y1);
389 
390  draw_arrow(x0, y0, x1, y1, angle, size, line, list);
391  }
392  }
393  }
394  }
395 
396  return narrows;
397 }
398 
399 /*!
400  \brief Calculate distance in pixels (on screen)
401  */
402 double dist_in_px(double dist)
403 {
404  int x, y;
405 
406  en_to_xy(region.map_west + dist, region.map_north, &x, &y);
407 
408  return sqrt(x * x);
409 }
410 
411 /*!
412  \brief Draw arrow
413  */
414 void draw_arrow(int x0, int y0, int x1, int y1, double angle, int size,
415  int line, struct robject_list *list)
416 {
417  double angle_symb;
418  struct robject *robj;
419 
420  robj = robj_alloc(TYPE_DIRECTION, 3);
421  robj->fid = line;
422 
423  angle_symb = angle - M_PI / 2.;
424  robj->point[0].x = (int)x1 + size * cos(angle_symb);
425  robj->point[0].y = (int)y1 - size * sin(angle_symb);
426 
427  robj->point[1].x = x0;
428  robj->point[1].y = y0;
429 
430  angle_symb = M_PI / 2. + angle;
431  robj->point[2].x = (int)x1 + size * cos(angle_symb);
432  robj->point[2].y = (int)y1 - size * sin(angle_symb);
433 
434  list_append(list, robj);
435 }
436 
437 /*!
438  \brief Draw area
439  */
440 void draw_area(struct Map_info *Map, int area, struct robject_list *list)
441 {
442  int i, centroid, isle;
443  int num_isles;
444  struct line_pnts *ipoints;
445 
446  struct robject *robj;
447 
448  if (!state.Points)
449  state.Points = Vect_new_line_struct();
450 
451  if (!Vect_area_alive(Map, area))
452  return;
453 
454  /* check for other centroids -- only area with one centroid is valid */
455  centroid = Vect_get_area_centroid(Map, area);
456  if (centroid <= 0)
457  return;
458 
459  ipoints = Vect_new_line_struct();
460  /* get area's boundary */
461  Vect_get_area_points(Map, area, state.Points);
462  robj = robj_alloc(TYPE_AREA, state.Points->n_points);
463  robj->fid = area;
464  robj_points(robj, state.Points);
465  list_append(list, robj);
466 
467  /* check for isles */
468  num_isles = Vect_get_area_num_isles(Map, area);
469  for (i = 0; i < num_isles; i++) {
470  isle = Vect_get_area_isle(Map, area, i);
471  if (!Vect_isle_alive(Map, isle))
472  continue;
473 
474  Vect_get_isle_points(Map, isle, ipoints);
475  robj = robj_alloc(TYPE_ISLE, ipoints->n_points);
476  robj->fid = -1;
477  robj_points(robj, ipoints);
478  list_append(list, robj);
479  }
480 
481  Vect_destroy_line_struct(ipoints);
482 }
483 
484 /*!
485  \brief convert EN -> XY
486  */
487 void robj_points(struct robject *robj, const struct line_pnts *points)
488 {
489  int i;
490  int x, y;
491 
492  for (i = 0; i < points->n_points; i++) {
493  en_to_xy(points->x[i], points->y[i], &x, &y);
494  robj->point[i].x = x;
495  robj->point[i].y = y;
496  }
497 }
#define NULL
Definition: ccmath.h:32
#define G_realloc(p, n)
Definition: defs/gis.h:96
#define G_malloc(n)
Definition: defs/gis.h:94
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
int Vect_get_line_nodes(struct Map_info *, int, int *, int *)
Get line nodes.
Definition: level_two.c:303
int Vect_get_node_coor(struct Map_info *, int, double *, double *, double *)
Get node coordinates.
Definition: level_two.c:274
double Vect_line_length(const struct line_pnts *)
Calculate line length, 3D-length in case of 3D vector line.
Definition: line.c:575
int Vect_area_alive(struct Map_info *, int)
Check if area is alive or dead (topological level required)
int Vect_point_on_line(const struct line_pnts *, double, double *, double *, double *, double *, double *)
Find point on line in the specified distance.
Definition: line.c:413
int Vect_get_line_type(struct Map_info *, int)
Get line type.
Definition: level_two.c:254
struct boxlist * Vect_new_boxlist(int)
Creates and initializes a struct boxlist.
void Vect_destroy_boxlist(struct boxlist *)
Frees all memory associated with a struct boxlist, including the struct itself.
int Vect_get_isle_points(struct Map_info *, int, struct line_pnts *)
Returns polygon array of points for given isle.
int Vect_get_area_points(struct Map_info *, int, struct line_pnts *)
Returns polygon array of points (outer ring) of given area.
int Vect_get_centroid_area(struct Map_info *, int)
Get area id the centroid is within.
Definition: level_two.c:429
int Vect_isle_alive(struct Map_info *, int)
Check if isle is alive or dead (topological level required)
int Vect_get_area_isle(struct Map_info *, int, int)
Returns isle id for area.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
int Vect_get_area_num_isles(struct Map_info *, int)
Returns number of isles for given area.
int Vect_line_alive(struct Map_info *, int)
Check if feature is alive or dead (topological level required)
int Vect_select_areas_by_box(struct Map_info *, const struct bound_box *, struct boxlist *)
Select areas with bounding boxes by box.
Definition: sindex.c:121
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
int Vect_select_lines_by_box(struct Map_info *, const struct bound_box *, int, struct boxlist *)
Select lines with bounding boxes by box.
Definition: sindex.c:32
int Vect_get_node_n_lines(struct Map_info *, int)
Get number of lines for node.
Definition: level_two.c:380
int Vect_get_area_centroid(struct Map_info *, int)
Returns centroid id for given area.
int Vect_get_line_areas(struct Map_info *, int, int *, int *)
Get area id on the left and right side of the boundary.
Definition: level_two.c:346
#define GV_CENTROID
Definition: dig_defines.h:186
#define GV_LINE
Definition: dig_defines.h:184
#define GV_POINT
Feature types used in memory on run time (may change)
Definition: dig_defines.h:183
#define GV_LINES
Definition: dig_defines.h:193
#define GV_BOUNDARY
Definition: dig_defines.h:185
#define GV_POINTS
Definition: dig_defines.h:192
#define FALSE
Definition: gis.h:83
#define M_PI
Definition: gis.h:158
struct state state
Definition: parser.c:103
struct list * list
Definition: read_list.c:24
if(!(yy_init))
Definition: sqlp.yy.c:775
Vector map info.
Definition: dig_structs.h:1243
Bounding box.
Definition: dig_structs.h:64
double W
West.
Definition: dig_structs.h:80
double S
South.
Definition: dig_structs.h:72
double N
North.
Definition: dig_structs.h:68
double E
East.
Definition: dig_structs.h:76
List of bounding boxes with id.
Definition: dig_structs.h:1723
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
Definition: manage.h:4
int nitems
Definition: vedit.h:60
struct robject ** item
Definition: vedit.h:61
Definition: vedit.h:50
int npoints
Definition: vedit.h:54
struct rpoint * point
Definition: vedit.h:55
int fid
Definition: vedit.h:52
int type
Definition: vedit.h:53
Definition: vedit.h:45
int x
Definition: vedit.h:47
int y
Definition: vedit.h:47
struct robject_list * Vedit_render_map(struct Map_info *Map, struct bound_box *box, int draw_flag, double center_easting, double center_northing, int map_width, int map_height, double map_res)
Render vector features into list.
#define DRAW_NODETWO
Definition: vedit.h:40
#define DRAW_BOUNDARYNO
Definition: vedit.h:33
#define TYPE_VERTEX
Definition: vedit.h:26
#define TYPE_BOUNDARYTWO
Definition: vedit.h:19
#define DRAW_VERTEX
Definition: vedit.h:41
#define TYPE_ISLE
Definition: vedit.h:28
#define DRAW_CENTROIDDUP
Definition: vedit.h:38
#define DRAW_NODEONE
Definition: vedit.h:39
#define TYPE_DIRECTION
Definition: vedit.h:29
#define TYPE_CENTROIDDUP
Definition: vedit.h:23
#define TYPE_AREA
Definition: vedit.h:27
#define DRAW_CENTROIDOUT
Definition: vedit.h:37
#define DRAW_POINT
Definition: vedit.h:31
#define DRAW_LINE
Definition: vedit.h:32
#define DRAW_AREA
Definition: vedit.h:42
#define DRAW_DIRECTION
Definition: vedit.h:43
#define TYPE_CENTROIDIN
Definition: vedit.h:21
#define TYPE_CENTROIDOUT
Definition: vedit.h:22
#define TYPE_LINE
Definition: vedit.h:17
#define DRAW_CENTROIDIN
Definition: vedit.h:36
#define TYPE_POINT
Definition: vedit.h:16
#define TYPE_BOUNDARYONE
Definition: vedit.h:20
#define TYPE_BOUNDARYNO
Definition: vedit.h:18
#define DRAW_BOUNDARYONE
Definition: vedit.h:35
#define TYPE_NODETWO
Definition: vedit.h:25
#define DRAW_BOUNDARYTWO
Definition: vedit.h:34
#define TYPE_NODEONE
Definition: vedit.h:24
#define x