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