GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-d6dec75dd4
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  G_free(obj);
209  return NULL;
210  }
211 
212  obj->npoints = state.Points->n_points;
213  obj->point =
214  (struct rpoint *)G_malloc(obj->npoints * sizeof(struct rpoint));
215  robj_points(obj, state.Points);
216 
217  return obj;
218 }
219 
220 /*!
221  \brief Convert geographic coordinates to the screen
222  */
223 void en_to_xy(double east, double north, int *x, int *y)
224 {
225  double n, w;
226 
227  w = region.center_easting - (region.map_width / 2) * region.map_res;
228  n = region.center_northing + (region.map_height / 2) * region.map_res;
229 
230  if (x)
231  *x = (east - w) / region.map_res;
232  if (y)
233  *y = (n - north) / region.map_res;
234 
235  return;
236 }
237 
238 /*!
239  \brief Draw line nodes
240  */
241 void draw_line_nodes(struct Map_info *Map, int line, int draw_flag,
242  struct robject_list *list)
243 {
244  unsigned int i;
245  int type, nodes[2];
246  int x, y;
247  double east, north;
248  struct robject *robj;
249 
250  if (Vect_get_line_type(Map, line) & GV_POINTS)
251  return;
252 
253  Vect_get_line_nodes(Map, line, &(nodes[0]), &(nodes[1]));
254 
255  for (i = 0; i < sizeof(nodes) / sizeof(int); i++) {
256  type = 0;
257  if (Vect_get_node_n_lines(Map, nodes[i]) == 1) {
258  if (draw_flag & DRAW_NODEONE) {
259  type = TYPE_NODEONE;
260  }
261  }
262  else {
263  if (draw_flag & DRAW_NODETWO) {
264  type = TYPE_NODETWO;
265  }
266  }
267 
268  if (type == 0)
269  continue;
270 
271  Vect_get_node_coor(Map, nodes[i], &east, &north, NULL);
272 
273  robj = robj_alloc(type, 1);
274  en_to_xy(east, north, &x, &y);
275  robj->fid = line;
276  robj->point->x = x;
277  robj->point->y = y;
278 
279  list_append(list, robj);
280  }
281 }
282 
283 /*!
284  \brief Append object to the list
285  */
286 void list_append(struct robject_list *list, struct robject *obj)
287 {
288  if (list->nitems >= state.nitems_alloc) {
289  state.nitems_alloc += 1000;
290  list->item = (struct robject **)G_realloc(
291  list->item, state.nitems_alloc * sizeof(struct robject *));
292  }
293  list->item[list->nitems++] = obj;
294 }
295 
296 /*!
297  \brief Allocate robject
298  */
299 struct robject *robj_alloc(int type, int npoints)
300 {
301  struct robject *robj;
302 
303  robj = (struct robject *)G_malloc(sizeof(struct robject));
304  robj->type = type;
305  robj->npoints = npoints;
306  robj->point = (struct rpoint *)G_malloc(npoints * sizeof(struct rpoint));
307 
308  return robj;
309 }
310 
311 /*!
312  \brief Draw line vertices
313  */
314 struct robject *draw_line_vertices(void)
315 {
316  int i;
317  int x, y;
318  struct robject *robj;
319 
320  robj =
321  robj_alloc(TYPE_VERTEX, state.Points->n_points - 2); /* ignore nodes */
322 
323  for (i = 1; i < state.Points->n_points - 1; i++) {
324  en_to_xy(state.Points->x[i], state.Points->y[i], &x, &y);
325  robj->point[i - 1].x = x;
326  robj->point[i - 1].y = y;
327  }
328 
329  return robj;
330 }
331 
332 /*!
333  \brief Draw line dirs
334  */
335 int draw_line_dir(struct robject_list *list, int line)
336 {
337  int narrows;
338  int size; /* arrow length in pixels */
339  int limit; /* segment length limit for drawing symbol (in pixels) */
340  double dist, angle, pos;
341  double e, n;
342  int x0, y0, x1, y1;
343 
344  narrows = 0;
345  size = 5;
346  limit = 5; /* 5px for line segment */
347 
348  dist = Vect_line_length(state.Points);
349  G_debug(5, " draw_line_dir() line=%d", line);
350 
351  if (dist_in_px(dist) >= limit) {
352  while (1) {
353  pos = (narrows + 1) * 8 * limit * region.map_res;
354 
355  if (Vect_point_on_line(state.Points, pos, &e, &n, NULL, NULL,
356  NULL) < 1) {
357  break;
358  }
359 
360  en_to_xy(e, n, &x0, &y0);
361 
362  if (Vect_point_on_line(state.Points,
363  pos - 3 * size * region.map_res, &e, &n,
364  NULL, &angle, NULL) < 1) {
365  break;
366  }
367 
368  en_to_xy(e, n, &x1, &y1);
369 
370  draw_arrow(x0, y0, x1, y1, angle, size, line, list);
371 
372  if (narrows > 1e2) /* low resolution, break */
373  break;
374 
375  narrows++;
376  }
377 
378  /* draw at least one arrow in the middle of line */
379  if (narrows < 1) {
380  dist /= 2.;
381  if (Vect_point_on_line(state.Points, dist, &e, &n, NULL, NULL,
382  NULL) > 0) {
383 
384  en_to_xy(e, n, &x0, &y0);
385 
386  if (Vect_point_on_line(state.Points,
387  dist - 3 * size * region.map_res, &e, &n,
388  NULL, &angle, NULL) > 0) {
389 
390  en_to_xy(e, n, &x1, &y1);
391 
392  draw_arrow(x0, y0, x1, y1, angle, size, line, list);
393  }
394  }
395  }
396  }
397 
398  return narrows;
399 }
400 
401 /*!
402  \brief Calculate distance in pixels (on screen)
403  */
404 double dist_in_px(double dist)
405 {
406  int x, y;
407 
408  en_to_xy(region.map_west + dist, region.map_north, &x, &y);
409 
410  return sqrt(x * x);
411 }
412 
413 /*!
414  \brief Draw arrow
415  */
416 void draw_arrow(int x0, int y0, int x1, int y1, double angle, int size,
417  int line, struct robject_list *list)
418 {
419  double angle_symb;
420  struct robject *robj;
421 
422  robj = robj_alloc(TYPE_DIRECTION, 3);
423  robj->fid = line;
424 
425  angle_symb = angle - M_PI / 2.;
426  robj->point[0].x = (int)x1 + size * cos(angle_symb);
427  robj->point[0].y = (int)y1 - size * sin(angle_symb);
428 
429  robj->point[1].x = x0;
430  robj->point[1].y = y0;
431 
432  angle_symb = M_PI / 2. + angle;
433  robj->point[2].x = (int)x1 + size * cos(angle_symb);
434  robj->point[2].y = (int)y1 - size * sin(angle_symb);
435 
436  list_append(list, robj);
437 }
438 
439 /*!
440  \brief Draw area
441  */
442 void draw_area(struct Map_info *Map, int area, struct robject_list *list)
443 {
444  int i, centroid, isle;
445  int num_isles;
446  struct line_pnts *ipoints;
447 
448  struct robject *robj;
449 
450  if (!state.Points)
451  state.Points = Vect_new_line_struct();
452 
453  if (!Vect_area_alive(Map, area))
454  return;
455 
456  /* check for other centroids -- only area with one centroid is valid */
457  centroid = Vect_get_area_centroid(Map, area);
458  if (centroid <= 0)
459  return;
460 
461  ipoints = Vect_new_line_struct();
462  /* get area's boundary */
463  Vect_get_area_points(Map, area, state.Points);
464  robj = robj_alloc(TYPE_AREA, state.Points->n_points);
465  robj->fid = area;
466  robj_points(robj, state.Points);
467  list_append(list, robj);
468 
469  /* check for isles */
470  num_isles = Vect_get_area_num_isles(Map, area);
471  for (i = 0; i < num_isles; i++) {
472  isle = Vect_get_area_isle(Map, area, i);
473  if (!Vect_isle_alive(Map, isle))
474  continue;
475 
476  Vect_get_isle_points(Map, isle, ipoints);
477  robj = robj_alloc(TYPE_ISLE, ipoints->n_points);
478  robj->fid = -1;
479  robj_points(robj, ipoints);
480  list_append(list, robj);
481  }
482 
483  Vect_destroy_line_struct(ipoints);
484 }
485 
486 /*!
487  \brief convert EN -> XY
488  */
489 void robj_points(struct robject *robj, const struct line_pnts *points)
490 {
491  int i;
492  int x, y;
493 
494  for (i = 0; i < points->n_points; i++) {
495  en_to_xy(points->x[i], points->y[i], &x, &y);
496  robj->point[i].x = x;
497  robj->point[i].y = y;
498  }
499 }
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#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