GRASS Programmer's Manual  6.4.2(2012)
vector/vedit/render.c
Go to the documentation of this file.
00001 
00014 #include <math.h>
00015 
00016 #include <grass/vedit.h>
00017 
00018 static struct _region
00019 {
00020     double center_easting;
00021     double center_northing;
00022     double map_west;
00023     double map_north;
00024     int map_width;
00025     int map_height;
00026     double map_res;
00027 } region;
00028 
00029 static struct _state
00030 {
00031     int nitems_alloc;
00032 
00033     int type;
00034     struct line_pnts *Points;
00035 } state;
00036 
00037 static struct robject *draw_line(struct Map_info *, int, int);
00038 static struct robject *draw_line_vertices();
00039 static void draw_line_nodes(struct Map_info *, int, int,
00040                             struct robject_list *);
00041 static int draw_line_dir(struct robject_list *, int);
00042 static void list_append(struct robject_list *, struct robject *);
00043 static struct robject *robj_alloc(int, int);
00044 static void robj_points(struct robject *, const struct line_pnts *);
00045 static double dist_in_px(double);
00046 static void en_to_xy(double, double, int *, int *);
00047 static void draw_arrow(int, int, int, int, double, int, int,
00048                        struct robject_list *);
00049 static void draw_area(struct Map_info *, int, struct robject_list *);
00050 
00061 struct robject_list *Vedit_render_map(struct Map_info *Map,
00062                                       struct bound_box *box, int draw_flag,
00063                                       double center_easting,
00064                                       double center_northing, int map_width,
00065                                       int map_height, double map_res)
00066 {
00067     int i, nfeat, fid;
00068     struct ilist *list;
00069     struct robject_list *list_obj;
00070     struct robject *robj;
00071 
00072     /* define region */
00073     region.center_easting = center_easting;
00074     region.center_northing = center_northing;
00075     region.map_width = map_width;
00076     region.map_height = map_height;
00077     region.map_res = map_res;
00078     region.map_west = center_easting - (map_width / 2.) * map_res;
00079     region.map_north = center_northing + (map_height / 2.) * map_res;
00080 
00081     list = Vect_new_list();
00082     list_obj = NULL;
00083     state.nitems_alloc = 1000;
00084 
00085     list_obj = (struct robject_list *)G_malloc(sizeof(struct robject_list));
00086     list_obj->nitems = 0;
00087     list_obj->item =
00088         (struct robject **)G_malloc(state.nitems_alloc *
00089                                     sizeof(struct robject *));
00090 
00091     /* area */
00092     if (draw_flag & DRAW_AREA) {
00093         nfeat = Vect_select_areas_by_box(Map, box, list);
00094         for (i = 0; i < nfeat; i++) {
00095             fid = list->value[i];
00096             draw_area(Map, fid, list_obj);
00097         }
00098     }
00099 
00100     /* draw lines inside of current display region */
00101     nfeat = Vect_select_lines_by_box(Map, box, GV_POINTS | GV_LINES,    // fixme
00102                                      list);
00103     G_debug(1, "Vedit_render_map(): region: w=%f, e=%f, s=%f, n=%f nlines=%d",
00104             box->W, box->E, box->S, box->N, nfeat);
00105 
00106     /* features */
00107     for (i = 0; i < list->n_values; i++) {
00108         fid = list->value[i];
00109         robj = draw_line(Map, fid, draw_flag);
00110         if (!robj)
00111             continue;
00112         list_append(list_obj, robj);
00113 
00114         if (state.type & GV_LINES) {
00115             /* vertices */
00116             if (draw_flag & DRAW_VERTEX) {
00117                 robj = draw_line_vertices();
00118                 robj->fid = fid;
00119                 if (robj)
00120                     list_append(list_obj, robj);
00121             }
00122             /* nodes */
00123             if (draw_flag & (DRAW_NODEONE | DRAW_NODETWO)) {
00124                 draw_line_nodes(Map, fid, draw_flag, list_obj);
00125             }
00126             /* direction */
00127             if (draw_flag & DRAW_DIRECTION) {
00128                 draw_line_dir(list_obj, fid);
00129             }
00130         }
00131     }
00132 
00133     list_obj->item =
00134         (struct robject **)G_realloc(list_obj->item,
00135                                      list_obj->nitems *
00136                                      sizeof(struct robject *));
00137 
00138     Vect_destroy_list(list);
00139 
00140     return list_obj;
00141 }
00142 
00146 struct robject *draw_line(struct Map_info *Map, int line, int draw_flag)
00147 {
00148     int draw;
00149     struct robject *obj;
00150 
00151     if (!state.Points)
00152         state.Points = Vect_new_line_struct();
00153 
00154     if (!Vect_line_alive(Map, line))
00155         return NULL;
00156 
00157     state.type = Vect_read_line(Map, state.Points, NULL, line);
00158 
00159     obj = (struct robject *)G_malloc(sizeof(struct robject));
00160     obj->fid = line;
00161     draw = FALSE;
00162     if (state.type & GV_LINES) {
00163         if (state.type == GV_LINE) {
00164             obj->type = TYPE_LINE;
00165             draw = draw_flag & DRAW_LINE;
00166         }
00167         else if (state.type == GV_BOUNDARY) {
00168             int left, right;
00169 
00170             Vect_get_line_areas(Map, line, &left, &right);
00171             if (left == 0 && right == 0) {
00172                 obj->type = TYPE_BOUNDARYNO;
00173                 draw = draw_flag & DRAW_BOUNDARYNO;
00174             }
00175             else if (left > 0 && right > 0) {
00176                 obj->type = TYPE_BOUNDARYTWO;
00177                 draw = draw_flag & DRAW_BOUNDARYTWO;
00178             }
00179             else {
00180                 obj->type = TYPE_BOUNDARYONE;
00181                 draw = draw_flag & DRAW_BOUNDARYONE;
00182             }
00183         }
00184     }
00185     else if (state.type & GV_POINTS) {
00186         if (state.type == GV_POINT) {
00187             obj->type = TYPE_POINT;
00188             draw = draw_flag & DRAW_POINT;
00189         }
00190         else if (state.type == GV_CENTROID) {
00191             int cret = Vect_get_centroid_area(Map, line);
00192 
00193             if (cret > 0) {     // -> area
00194                 obj->type = TYPE_CENTROIDIN;
00195                 draw = draw_flag & DRAW_CENTROIDIN;
00196             }
00197             else if (cret == 0) {
00198                 obj->type = TYPE_CENTROIDOUT;
00199                 draw = draw_flag & DRAW_CENTROIDOUT;
00200             }
00201             else {
00202                 obj->type = TYPE_CENTROIDDUP;
00203                 draw = draw_flag & DRAW_CENTROIDDUP;
00204             }
00205         }
00206     }
00207     G_debug(3, "  draw_line(): type=%d rtype=%d npoints=%d draw=%d",
00208             state.type, obj->type, state.Points->n_points, draw);
00209 
00210     if (!draw)
00211         return NULL;
00212 
00213     obj->npoints = state.Points->n_points;
00214     obj->point =
00215         (struct rpoint *)G_malloc(obj->npoints * sizeof(struct rpoint));
00216     robj_points(obj, state.Points);
00217 
00218     return obj;
00219 }
00220 
00224 void en_to_xy(double east, double north, int *x, int *y)
00225 {
00226     double n, w;
00227 
00228     w = region.center_easting - (region.map_width / 2) * region.map_res;
00229     n = region.center_northing + (region.map_height / 2) * region.map_res;
00230 
00231     if (x)
00232         *x = (east - w) / region.map_res;
00233     if (y)
00234         *y = (n - north) / region.map_res;
00235 
00236     return;
00237 }
00238 
00242 void draw_line_nodes(struct Map_info *Map, int line, int draw_flag,
00243                      struct robject_list *list)
00244 {
00245     unsigned int i;
00246     int type, nodes[2];
00247     int x, y;
00248     double east, north;
00249     struct robject *robj;
00250 
00251     Vect_get_line_nodes(Map, line, &(nodes[0]), &(nodes[1]));
00252     
00253     for (i = 0; i < sizeof(nodes) / sizeof(int); i++) {
00254         type = 0;
00255         if (Vect_get_node_n_lines(Map, nodes[i]) == 1) {
00256             if (draw_flag & DRAW_NODEONE) {
00257                 type = TYPE_NODEONE;
00258             }
00259         }
00260         else {
00261             if (draw_flag & DRAW_NODETWO) {
00262                 type = TYPE_NODETWO;
00263             }
00264         }
00265 
00266         if (type == 0)
00267             continue;
00268 
00269         Vect_get_node_coor(Map, nodes[i], &east, &north, NULL);
00270 
00271         robj = robj_alloc(type, 1);
00272         en_to_xy(east, north, &x, &y);
00273         robj->fid = line;
00274         robj->point->x = x;
00275         robj->point->y = y;
00276 
00277         list_append(list, robj);
00278     }
00279 }
00280 
00284 void list_append(struct robject_list *list, struct robject *obj)
00285 {
00286     if (list->nitems >= state.nitems_alloc) {
00287         state.nitems_alloc += 1000;
00288         list->item =
00289             (struct robject **)G_realloc(list->item,
00290                                          state.nitems_alloc *
00291                                          sizeof(struct robject *));
00292     }
00293     list->item[list->nitems++] = obj;
00294 }
00295 
00299 struct robject *robj_alloc(int type, int npoints)
00300 {
00301     struct robject *robj;
00302 
00303     robj = (struct robject *)G_malloc(sizeof(struct robject));
00304     robj->type = type;
00305     robj->npoints = npoints;
00306     robj->point = (struct rpoint *)G_malloc(npoints * sizeof(struct rpoint));
00307 
00308     return robj;
00309 }
00310 
00314 struct robject *draw_line_vertices()
00315 {
00316     int i;
00317     int x, y;
00318     struct robject *robj;
00319 
00320     robj = robj_alloc(TYPE_VERTEX, state.Points->n_points - 2); /* ignore nodes */
00321 
00322     for (i = 1; i < state.Points->n_points - 1; i++) {
00323         en_to_xy(state.Points->x[i], state.Points->y[i], &x, &y);
00324         robj->point[i - 1].x = x;
00325         robj->point[i - 1].y = y;
00326     }
00327 
00328     return robj;
00329 }
00330 
00334 int draw_line_dir(struct robject_list *list, int line)
00335 {
00336     int narrows;
00337     int size;                   /* arrow length in pixels */
00338     int limit;                  /* segment length limit for drawing symbol (in pixels) */
00339     double dist, angle, pos;
00340     double e, n;
00341     int x0, y0, x1, y1;
00342 
00343     narrows = 0;
00344     size = 5;
00345     limit = 5;                  // 5px for line segment
00346 
00347     dist = Vect_line_length(state.Points);
00348     G_debug(5, "  draw_line_dir() line=%d", line);
00349                                                   
00350     if (dist_in_px(dist) >= limit) {
00351         while (1) {
00352             pos = (narrows + 1) * 8 * limit * region.map_res;
00353 
00354             if (Vect_point_on_line(state.Points, pos,
00355                                    &e, &n, NULL, NULL, NULL) < 1) {
00356                 break;
00357             }
00358 
00359             en_to_xy(e, n, &x0, &y0);
00360 
00361             if (Vect_point_on_line
00362                 (state.Points, pos - 3 * size * region.map_res, &e, &n, NULL,
00363                  &angle, NULL) < 1) {
00364                 break;
00365             }
00366 
00367             en_to_xy(e, n, &x1, &y1);
00368 
00369             draw_arrow(x0, y0, x1, y1, angle, size, line, list);
00370 
00371             if (narrows > 1e2)  // low resolution, break
00372                 break;
00373 
00374             narrows++;
00375         }
00376 
00377         // draw at least one arrow in the middle of line
00378         if (narrows < 1) {
00379             dist /= 2.;
00380             if (Vect_point_on_line(state.Points, dist,
00381                                    &e, &n, NULL, NULL, NULL) > 0) {
00382 
00383                 en_to_xy(e, n, &x0, &y0);
00384 
00385                 if (Vect_point_on_line
00386                     (state.Points, dist - 3 * size * region.map_res, &e, &n,
00387                      NULL, &angle, NULL) > 0) {
00388 
00389                     en_to_xy(e, n, &x1, &y1);
00390 
00391                     draw_arrow(x0, y0, x1, y1, angle, size, line, list);
00392                 }
00393             }
00394         }
00395     }
00396 
00397     return narrows;
00398 }
00399 
00403 double dist_in_px(double dist)
00404 {
00405     int x, y;
00406 
00407     en_to_xy(region.map_west + dist, region.map_north, &x, &y);
00408 
00409     return sqrt(x * x);
00410 }
00411 
00415 void draw_arrow(int x0, int y0, int x1, int y1, double angle, int size, int line,
00416                 struct robject_list *list)
00417 {
00418     double angle_symb;
00419     struct robject *robj;
00420 
00421     robj = robj_alloc(TYPE_DIRECTION, 3);
00422     robj->fid = line;
00423     
00424     angle_symb = angle - M_PI / 2.;
00425     robj->point[0].x = (int)x1 + size * cos(angle_symb);
00426     robj->point[0].y = (int)y1 - size * sin(angle_symb);
00427 
00428     robj->point[1].x = x0;
00429     robj->point[1].y = y0;
00430 
00431     angle_symb = M_PI / 2. + angle;
00432     robj->point[2].x = (int)x1 + size * cos(angle_symb);
00433     robj->point[2].y = (int)y1 - size * sin(angle_symb);
00434 
00435     list_append(list, robj);
00436 }
00437 
00441 void draw_area(struct Map_info *Map, int area, struct robject_list *list)
00442 {
00443     int i, centroid, isle;
00444     int num_isles;
00445     struct line_pnts *ipoints;
00446 
00447     struct robject *robj;
00448 
00449     if (!state.Points)
00450         state.Points = Vect_new_line_struct();
00451 
00452     if (!Vect_area_alive(Map, area))
00453         return;
00454 
00455     /* check for other centroids -- only area with one centroid is valid */
00456     centroid = Vect_get_area_centroid(Map, area);
00457     if (centroid <= 0)
00458         return;
00459 
00460     ipoints = Vect_new_line_struct();
00461     /* get area's boundary */
00462     Vect_get_area_points(Map, area, state.Points);
00463     robj = robj_alloc(TYPE_AREA, state.Points->n_points);
00464     robj_points(robj, state.Points);
00465     list_append(list, robj);
00466 
00467     /* check for isles */
00468     num_isles = Vect_get_area_num_isles(Map, area);
00469     for (i = 0; i < num_isles; i++) {
00470         isle = Vect_get_area_isle(Map, area, i);
00471         if (!Vect_isle_alive(Map, isle))
00472             continue;
00473 
00474         Vect_get_isle_points(Map, isle, ipoints);
00475         robj = robj_alloc(TYPE_ISLE, ipoints->n_points);
00476         robj_points(robj, ipoints);
00477         list_append(list, robj);
00478     }
00479 
00480     Vect_destroy_line_struct(ipoints);
00481 }
00482 
00486 void robj_points(struct robject *robj, const struct line_pnts *points)
00487 {
00488     int i;
00489     int x, y;
00490 
00491     for (i = 0; i < points->n_points; i++) {
00492         en_to_xy(points->x[i], points->y[i], &x, &y);
00493         robj->point[i].x = x;
00494         robj->point[i].y = y;
00495     }
00496 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines