123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- /*!
- \file lib/vector/vedit/render.c
- \brief Vedit library - render vector features (used by wxGUI digitizer)
- (C) 2010-2011 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- \author Martin Landa <landa.martin gmail.com>
- */
- #include <math.h>
- #include <grass/vedit.h>
- static struct _region
- {
- double center_easting;
- double center_northing;
- double map_west;
- double map_north;
- int map_width;
- int map_height;
- double map_res;
- } region;
- static struct _state
- {
- int nitems_alloc;
- int type;
- struct line_pnts *Points;
- } state;
- static struct robject *draw_line(struct Map_info *, int, int);
- static struct robject *draw_line_vertices();
- static void draw_line_nodes(struct Map_info *, int, int,
- struct robject_list *);
- static int draw_line_dir(struct robject_list *, int);
- static void list_append(struct robject_list *, struct robject *);
- static struct robject *robj_alloc(int, int);
- static void robj_points(struct robject *, const struct line_pnts *);
- static double dist_in_px(double);
- static void en_to_xy(double, double, int *, int *);
- static void draw_arrow(int, int, int, int, double, int, int,
- struct robject_list *);
- static void draw_area(struct Map_info *, int, struct robject_list *);
- /*!
- \brief Render vector features into list
-
- \param Map pointer to Map_info structure
- \param box bounding box of region to be rendered
- \param draw_flag types of objects to be rendered (see vedit.h)
- \param center_easing, center_northing, map_width, map_height, map_res values used for conversion en->xy
-
- \return pointer to robject_list structure
- */
- 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)
- {
- int i, nfeat, fid;
- struct boxlist *list;
- struct robject_list *list_obj;
- struct robject *robj;
- /* define region */
- region.center_easting = center_easting;
- region.center_northing = center_northing;
- region.map_width = map_width;
- region.map_height = map_height;
- region.map_res = map_res;
- region.map_west = center_easting - (map_width / 2.) * map_res;
- region.map_north = center_northing + (map_height / 2.) * map_res;
- list = Vect_new_boxlist(0);
- list_obj = NULL;
- state.nitems_alloc = 1000;
- list_obj = (struct robject_list *)G_malloc(sizeof(struct robject_list));
- list_obj->nitems = 0;
- list_obj->item =
- (struct robject **)G_malloc(state.nitems_alloc *
- sizeof(struct robject *));
- /* area */
- if (draw_flag & DRAW_AREA) {
- nfeat = Vect_select_areas_by_box(Map, box, list);
- for (i = 0; i < nfeat; i++) {
- fid = list->id[i];
- draw_area(Map, fid, list_obj);
- }
- }
- /* draw lines inside of current display region */
- nfeat = Vect_select_lines_by_box(Map, box, GV_POINTS | GV_LINES, /* fixme */
- list);
- G_debug(1, "Vedit_render_map(): region: w=%f, e=%f, s=%f, n=%f nlines=%d",
- box->W, box->E, box->S, box->N, nfeat);
- /* features */
- for (i = 0; i < list->n_values; i++) {
- fid = list->id[i];
- robj = draw_line(Map, fid, draw_flag);
- if (!robj)
- continue;
- list_append(list_obj, robj);
- if (state.type & GV_LINES) {
- /* vertices */
- if (draw_flag & DRAW_VERTEX) {
- robj = draw_line_vertices();
- robj->fid = fid;
- if (robj)
- list_append(list_obj, robj);
- }
- /* nodes */
- if (draw_flag & (DRAW_NODEONE | DRAW_NODETWO)) {
- draw_line_nodes(Map, fid, draw_flag, list_obj);
- }
- /* direction */
- if (draw_flag & DRAW_DIRECTION) {
- draw_line_dir(list_obj, fid);
- }
- }
- }
- list_obj->item =
- (struct robject **)G_realloc(list_obj->item,
- list_obj->nitems *
- sizeof(struct robject *));
- G_debug(1, "Vedit_render_map(): -> nitems = %d",
- list_obj->nitems);
-
- Vect_destroy_boxlist(list);
- return list_obj;
- }
- /*!
- \brief Draw one feature
- */
- struct robject *draw_line(struct Map_info *Map, int line, int draw_flag)
- {
- int draw;
- struct robject *obj;
- if (!state.Points)
- state.Points = Vect_new_line_struct();
- if (!Vect_line_alive(Map, line))
- return NULL;
- state.type = Vect_read_line(Map, state.Points, NULL, line);
- obj = (struct robject *)G_malloc(sizeof(struct robject));
- obj->fid = line;
- draw = FALSE;
- if (state.type & GV_LINES) {
- if (state.type == GV_LINE) {
- obj->type = TYPE_LINE;
- draw = draw_flag & DRAW_LINE;
- }
- else if (state.type == GV_BOUNDARY) {
- int left, right;
- Vect_get_line_areas(Map, line, &left, &right);
- if (left == 0 && right == 0) {
- obj->type = TYPE_BOUNDARYNO;
- draw = draw_flag & DRAW_BOUNDARYNO;
- }
- else if (left > 0 && right > 0) {
- obj->type = TYPE_BOUNDARYTWO;
- draw = draw_flag & DRAW_BOUNDARYTWO;
- }
- else {
- obj->type = TYPE_BOUNDARYONE;
- draw = draw_flag & DRAW_BOUNDARYONE;
- }
- }
- }
- else if (state.type & GV_POINTS) {
- if (state.type == GV_POINT) {
- obj->type = TYPE_POINT;
- draw = draw_flag & DRAW_POINT;
- }
- else if (state.type == GV_CENTROID) {
- int cret = Vect_get_centroid_area(Map, line);
- if (cret > 0) { /* -> area */
- obj->type = TYPE_CENTROIDIN;
- draw = draw_flag & DRAW_CENTROIDIN;
- }
- else if (cret == 0) {
- obj->type = TYPE_CENTROIDOUT;
- draw = draw_flag & DRAW_CENTROIDOUT;
- }
- else {
- obj->type = TYPE_CENTROIDDUP;
- draw = draw_flag & DRAW_CENTROIDDUP;
- }
- }
- }
- G_debug(3, " draw_line(): type=%d rtype=%d npoints=%d draw=%d",
- state.type, obj->type, state.Points->n_points, draw);
- if (!draw)
- return NULL;
- obj->npoints = state.Points->n_points;
- obj->point =
- (struct rpoint *)G_malloc(obj->npoints * sizeof(struct rpoint));
- robj_points(obj, state.Points);
- return obj;
- }
- /*!
- \brief Convert geographic coordinates to the screen
- */
- void en_to_xy(double east, double north, int *x, int *y)
- {
- double n, w;
- w = region.center_easting - (region.map_width / 2) * region.map_res;
- n = region.center_northing + (region.map_height / 2) * region.map_res;
- if (x)
- *x = (east - w) / region.map_res;
- if (y)
- *y = (n - north) / region.map_res;
- return;
- }
- /*!
- \brief Draw line nodes
- */
- void draw_line_nodes(struct Map_info *Map, int line, int draw_flag,
- struct robject_list *list)
- {
- unsigned int i;
- int type, nodes[2];
- int x, y;
- double east, north;
- struct robject *robj;
- if (Vect_get_line_type(Map, line) & GV_POINTS)
- return;
- Vect_get_line_nodes(Map, line, &(nodes[0]), &(nodes[1]));
-
- for (i = 0; i < sizeof(nodes) / sizeof(int); i++) {
- type = 0;
- if (Vect_get_node_n_lines(Map, nodes[i]) == 1) {
- if (draw_flag & DRAW_NODEONE) {
- type = TYPE_NODEONE;
- }
- }
- else {
- if (draw_flag & DRAW_NODETWO) {
- type = TYPE_NODETWO;
- }
- }
- if (type == 0)
- continue;
- Vect_get_node_coor(Map, nodes[i], &east, &north, NULL);
- robj = robj_alloc(type, 1);
- en_to_xy(east, north, &x, &y);
- robj->fid = line;
- robj->point->x = x;
- robj->point->y = y;
- list_append(list, robj);
- }
- }
- /*!
- \brief Append object to the list
- */
- void list_append(struct robject_list *list, struct robject *obj)
- {
- if (list->nitems >= state.nitems_alloc) {
- state.nitems_alloc += 1000;
- list->item =
- (struct robject **)G_realloc(list->item,
- state.nitems_alloc *
- sizeof(struct robject *));
- }
- list->item[list->nitems++] = obj;
- }
- /*!
- \brief Allocate robject
- */
- struct robject *robj_alloc(int type, int npoints)
- {
- struct robject *robj;
- robj = (struct robject *)G_malloc(sizeof(struct robject));
- robj->type = type;
- robj->npoints = npoints;
- robj->point = (struct rpoint *)G_malloc(npoints * sizeof(struct rpoint));
- return robj;
- }
- /*!
- \brief Draw line vertices
- */
- struct robject *draw_line_vertices()
- {
- int i;
- int x, y;
- struct robject *robj;
- robj = robj_alloc(TYPE_VERTEX, state.Points->n_points - 2); /* ignore nodes */
- for (i = 1; i < state.Points->n_points - 1; i++) {
- en_to_xy(state.Points->x[i], state.Points->y[i], &x, &y);
- robj->point[i - 1].x = x;
- robj->point[i - 1].y = y;
- }
- return robj;
- }
- /*!
- \brief Draw line dirs
- */
- int draw_line_dir(struct robject_list *list, int line)
- {
- int narrows;
- int size; /* arrow length in pixels */
- int limit; /* segment length limit for drawing symbol (in pixels) */
- double dist, angle, pos;
- double e, n;
- int x0, y0, x1, y1;
- narrows = 0;
- size = 5;
- limit = 5; /* 5px for line segment */
- dist = Vect_line_length(state.Points);
- G_debug(5, " draw_line_dir() line=%d", line);
-
- if (dist_in_px(dist) >= limit) {
- while (1) {
- pos = (narrows + 1) * 8 * limit * region.map_res;
- if (Vect_point_on_line(state.Points, pos,
- &e, &n, NULL, NULL, NULL) < 1) {
- break;
- }
- en_to_xy(e, n, &x0, &y0);
- if (Vect_point_on_line
- (state.Points, pos - 3 * size * region.map_res, &e, &n, NULL,
- &angle, NULL) < 1) {
- break;
- }
- en_to_xy(e, n, &x1, &y1);
- draw_arrow(x0, y0, x1, y1, angle, size, line, list);
- if (narrows > 1e2) /* low resolution, break */
- break;
- narrows++;
- }
- /* draw at least one arrow in the middle of line */
- if (narrows < 1) {
- dist /= 2.;
- if (Vect_point_on_line(state.Points, dist,
- &e, &n, NULL, NULL, NULL) > 0) {
- en_to_xy(e, n, &x0, &y0);
- if (Vect_point_on_line
- (state.Points, dist - 3 * size * region.map_res, &e, &n,
- NULL, &angle, NULL) > 0) {
- en_to_xy(e, n, &x1, &y1);
- draw_arrow(x0, y0, x1, y1, angle, size, line, list);
- }
- }
- }
- }
- return narrows;
- }
- /*!
- \brief Calculate distance in pixels (on screen)
- */
- double dist_in_px(double dist)
- {
- int x, y;
- en_to_xy(region.map_west + dist, region.map_north, &x, &y);
- return sqrt(x * x);
- }
- /*!
- \brief Draw arrow
- */
- void draw_arrow(int x0, int y0, int x1, int y1, double angle, int size, int line,
- struct robject_list *list)
- {
- double angle_symb;
- struct robject *robj;
- robj = robj_alloc(TYPE_DIRECTION, 3);
- robj->fid = line;
-
- angle_symb = angle - M_PI / 2.;
- robj->point[0].x = (int)x1 + size * cos(angle_symb);
- robj->point[0].y = (int)y1 - size * sin(angle_symb);
- robj->point[1].x = x0;
- robj->point[1].y = y0;
- angle_symb = M_PI / 2. + angle;
- robj->point[2].x = (int)x1 + size * cos(angle_symb);
- robj->point[2].y = (int)y1 - size * sin(angle_symb);
- list_append(list, robj);
- }
- /*!
- \brief Draw area
- */
- void draw_area(struct Map_info *Map, int area, struct robject_list *list)
- {
- int i, centroid, isle;
- int num_isles;
- struct line_pnts *ipoints;
- struct robject *robj;
- if (!state.Points)
- state.Points = Vect_new_line_struct();
- if (!Vect_area_alive(Map, area))
- return;
- /* check for other centroids -- only area with one centroid is valid */
- centroid = Vect_get_area_centroid(Map, area);
- if (centroid <= 0)
- return;
- ipoints = Vect_new_line_struct();
- /* get area's boundary */
- Vect_get_area_points(Map, area, state.Points);
- robj = robj_alloc(TYPE_AREA, state.Points->n_points);
- robj->fid = area;
- robj_points(robj, state.Points);
- list_append(list, robj);
- /* check for isles */
- num_isles = Vect_get_area_num_isles(Map, area);
- for (i = 0; i < num_isles; i++) {
- isle = Vect_get_area_isle(Map, area, i);
- if (!Vect_isle_alive(Map, isle))
- continue;
- Vect_get_isle_points(Map, isle, ipoints);
- robj = robj_alloc(TYPE_ISLE, ipoints->n_points);
- robj->fid = -1;
- robj_points(robj, ipoints);
- list_append(list, robj);
- }
- Vect_destroy_line_struct(ipoints);
- }
- /*!
- \brief convert EN -> XY
- */
- void robj_points(struct robject *robj, const struct line_pnts *points)
- {
- int i;
- int x, y;
- for (i = 0; i < points->n_points; i++) {
- en_to_xy(points->x[i], points->y[i], &x, &y);
- robj->point[i].x = x;
- robj->point[i].y = y;
- }
- }
|