GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
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     G_debug(1, "Vedit_render_map(): -> nitems = %d",
00139             list_obj->nitems);
00140     
00141     Vect_destroy_list(list);
00142     
00143     return list_obj;
00144 }
00145 
00149 struct robject *draw_line(struct Map_info *Map, int line, int draw_flag)
00150 {
00151     int draw;
00152     struct robject *obj;
00153 
00154     if (!state.Points)
00155         state.Points = Vect_new_line_struct();
00156 
00157     if (!Vect_line_alive(Map, line))
00158         return NULL;
00159 
00160     state.type = Vect_read_line(Map, state.Points, NULL, line);
00161 
00162     obj = (struct robject *)G_malloc(sizeof(struct robject));
00163     obj->fid = line;
00164     draw = FALSE;
00165     if (state.type & GV_LINES) {
00166         if (state.type == GV_LINE) {
00167             obj->type = TYPE_LINE;
00168             draw = draw_flag & DRAW_LINE;
00169         }
00170         else if (state.type == GV_BOUNDARY) {
00171             int left, right;
00172 
00173             Vect_get_line_areas(Map, line, &left, &right);
00174             if (left == 0 && right == 0) {
00175                 obj->type = TYPE_BOUNDARYNO;
00176                 draw = draw_flag & DRAW_BOUNDARYNO;
00177             }
00178             else if (left > 0 && right > 0) {
00179                 obj->type = TYPE_BOUNDARYTWO;
00180                 draw = draw_flag & DRAW_BOUNDARYTWO;
00181             }
00182             else {
00183                 obj->type = TYPE_BOUNDARYONE;
00184                 draw = draw_flag & DRAW_BOUNDARYONE;
00185             }
00186         }
00187     }
00188     else if (state.type & GV_POINTS) {
00189         if (state.type == GV_POINT) {
00190             obj->type = TYPE_POINT;
00191             draw = draw_flag & DRAW_POINT;
00192         }
00193         else if (state.type == GV_CENTROID) {
00194             int cret = Vect_get_centroid_area(Map, line);
00195 
00196             if (cret > 0) {     // -> area
00197                 obj->type = TYPE_CENTROIDIN;
00198                 draw = draw_flag & DRAW_CENTROIDIN;
00199             }
00200             else if (cret == 0) {
00201                 obj->type = TYPE_CENTROIDOUT;
00202                 draw = draw_flag & DRAW_CENTROIDOUT;
00203             }
00204             else {
00205                 obj->type = TYPE_CENTROIDDUP;
00206                 draw = draw_flag & DRAW_CENTROIDDUP;
00207             }
00208         }
00209     }
00210     G_debug(3, "  draw_line(): type=%d rtype=%d npoints=%d draw=%d",
00211             state.type, obj->type, state.Points->n_points, draw);
00212 
00213     if (!draw)
00214         return NULL;
00215 
00216     obj->npoints = state.Points->n_points;
00217     obj->point =
00218         (struct rpoint *)G_malloc(obj->npoints * sizeof(struct rpoint));
00219     robj_points(obj, state.Points);
00220 
00221     return obj;
00222 }
00223 
00227 void en_to_xy(double east, double north, int *x, int *y)
00228 {
00229     double n, w;
00230 
00231     w = region.center_easting - (region.map_width / 2) * region.map_res;
00232     n = region.center_northing + (region.map_height / 2) * region.map_res;
00233 
00234     if (x)
00235         *x = (east - w) / region.map_res;
00236     if (y)
00237         *y = (n - north) / region.map_res;
00238 
00239     return;
00240 }
00241 
00245 void draw_line_nodes(struct Map_info *Map, int line, int draw_flag,
00246                      struct robject_list *list)
00247 {
00248     unsigned int i;
00249     int type, nodes[2];
00250     int x, y;
00251     double east, north;
00252     struct robject *robj;
00253 
00254     Vect_get_line_nodes(Map, line, &(nodes[0]), &(nodes[1]));
00255     
00256     for (i = 0; i < sizeof(nodes) / sizeof(int); i++) {
00257         type = 0;
00258         if (Vect_get_node_n_lines(Map, nodes[i]) == 1) {
00259             if (draw_flag & DRAW_NODEONE) {
00260                 type = TYPE_NODEONE;
00261             }
00262         }
00263         else {
00264             if (draw_flag & DRAW_NODETWO) {
00265                 type = TYPE_NODETWO;
00266             }
00267         }
00268 
00269         if (type == 0)
00270             continue;
00271 
00272         Vect_get_node_coor(Map, nodes[i], &east, &north, NULL);
00273 
00274         robj = robj_alloc(type, 1);
00275         en_to_xy(east, north, &x, &y);
00276         robj->fid = line;
00277         robj->point->x = x;
00278         robj->point->y = y;
00279 
00280         list_append(list, robj);
00281     }
00282 }
00283 
00287 void list_append(struct robject_list *list, struct robject *obj)
00288 {
00289     if (list->nitems >= state.nitems_alloc) {
00290         state.nitems_alloc += 1000;
00291         list->item =
00292             (struct robject **)G_realloc(list->item,
00293                                          state.nitems_alloc *
00294                                          sizeof(struct robject *));
00295     }
00296     list->item[list->nitems++] = obj;
00297 }
00298 
00302 struct robject *robj_alloc(int type, int npoints)
00303 {
00304     struct robject *robj;
00305 
00306     robj = (struct robject *)G_malloc(sizeof(struct robject));
00307     robj->type = type;
00308     robj->npoints = npoints;
00309     robj->point = (struct rpoint *)G_malloc(npoints * sizeof(struct rpoint));
00310 
00311     return robj;
00312 }
00313 
00317 struct robject *draw_line_vertices()
00318 {
00319     int i;
00320     int x, y;
00321     struct robject *robj;
00322 
00323     robj = robj_alloc(TYPE_VERTEX, state.Points->n_points - 2); /* ignore nodes */
00324 
00325     for (i = 1; i < state.Points->n_points - 1; i++) {
00326         en_to_xy(state.Points->x[i], state.Points->y[i], &x, &y);
00327         robj->point[i - 1].x = x;
00328         robj->point[i - 1].y = y;
00329     }
00330 
00331     return robj;
00332 }
00333 
00337 int draw_line_dir(struct robject_list *list, int line)
00338 {
00339     int narrows;
00340     int size;                   /* arrow length in pixels */
00341     int limit;                  /* segment length limit for drawing symbol (in pixels) */
00342     double dist, angle, pos;
00343     double e, n;
00344     int x0, y0, x1, y1;
00345 
00346     narrows = 0;
00347     size = 5;
00348     limit = 5;                  // 5px for line segment
00349 
00350     dist = Vect_line_length(state.Points);
00351     G_debug(5, "  draw_line_dir() line=%d", line);
00352                                                   
00353     if (dist_in_px(dist) >= limit) {
00354         while (1) {
00355             pos = (narrows + 1) * 8 * limit * region.map_res;
00356 
00357             if (Vect_point_on_line(state.Points, pos,
00358                                    &e, &n, NULL, NULL, NULL) < 1) {
00359                 break;
00360             }
00361 
00362             en_to_xy(e, n, &x0, &y0);
00363 
00364             if (Vect_point_on_line
00365                 (state.Points, pos - 3 * size * region.map_res, &e, &n, NULL,
00366                  &angle, NULL) < 1) {
00367                 break;
00368             }
00369 
00370             en_to_xy(e, n, &x1, &y1);
00371 
00372             draw_arrow(x0, y0, x1, y1, angle, size, line, list);
00373 
00374             if (narrows > 1e2)  // low resolution, break
00375                 break;
00376 
00377             narrows++;
00378         }
00379 
00380         // draw at least one arrow in the middle of line
00381         if (narrows < 1) {
00382             dist /= 2.;
00383             if (Vect_point_on_line(state.Points, dist,
00384                                    &e, &n, NULL, NULL, NULL) > 0) {
00385 
00386                 en_to_xy(e, n, &x0, &y0);
00387 
00388                 if (Vect_point_on_line
00389                     (state.Points, dist - 3 * size * region.map_res, &e, &n,
00390                      NULL, &angle, NULL) > 0) {
00391 
00392                     en_to_xy(e, n, &x1, &y1);
00393 
00394                     draw_arrow(x0, y0, x1, y1, angle, size, line, list);
00395                 }
00396             }
00397         }
00398     }
00399 
00400     return narrows;
00401 }
00402 
00406 double dist_in_px(double dist)
00407 {
00408     int x, y;
00409 
00410     en_to_xy(region.map_west + dist, region.map_north, &x, &y);
00411 
00412     return sqrt(x * x);
00413 }
00414 
00418 void draw_arrow(int x0, int y0, int x1, int y1, double angle, int size, int line,
00419                 struct robject_list *list)
00420 {
00421     double angle_symb;
00422     struct robject *robj;
00423 
00424     robj = robj_alloc(TYPE_DIRECTION, 3);
00425     robj->fid = line;
00426     
00427     angle_symb = angle - M_PI / 2.;
00428     robj->point[0].x = (int)x1 + size * cos(angle_symb);
00429     robj->point[0].y = (int)y1 - size * sin(angle_symb);
00430 
00431     robj->point[1].x = x0;
00432     robj->point[1].y = y0;
00433 
00434     angle_symb = M_PI / 2. + angle;
00435     robj->point[2].x = (int)x1 + size * cos(angle_symb);
00436     robj->point[2].y = (int)y1 - size * sin(angle_symb);
00437 
00438     list_append(list, robj);
00439 }
00440 
00444 void draw_area(struct Map_info *Map, int area, struct robject_list *list)
00445 {
00446     int i, centroid, isle;
00447     int num_isles;
00448     struct line_pnts *ipoints;
00449 
00450     struct robject *robj;
00451 
00452     if (!state.Points)
00453         state.Points = Vect_new_line_struct();
00454 
00455     if (!Vect_area_alive(Map, area))
00456         return;
00457 
00458     /* check for other centroids -- only area with one centroid is valid */
00459     centroid = Vect_get_area_centroid(Map, area);
00460     if (centroid <= 0)
00461         return;
00462 
00463     ipoints = Vect_new_line_struct();
00464     /* get area's boundary */
00465     Vect_get_area_points(Map, area, state.Points);
00466     robj = robj_alloc(TYPE_AREA, state.Points->n_points);
00467     robj->fid = centroid;
00468     robj_points(robj, state.Points);
00469     list_append(list, robj);
00470 
00471     /* check for isles */
00472     num_isles = Vect_get_area_num_isles(Map, area);
00473     for (i = 0; i < num_isles; i++) {
00474         isle = Vect_get_area_isle(Map, area, i);
00475         if (!Vect_isle_alive(Map, isle))
00476             continue;
00477 
00478         Vect_get_isle_points(Map, isle, ipoints);
00479         robj = robj_alloc(TYPE_ISLE, ipoints->n_points);
00480         robj->fid = -1;
00481         robj_points(robj, ipoints);
00482         list_append(list, robj);
00483     }
00484 
00485     Vect_destroy_line_struct(ipoints);
00486 }
00487 
00491 void robj_points(struct robject *robj, const struct line_pnts *points)
00492 {
00493     int i;
00494     int x, y;
00495 
00496     for (i = 0; i < points->n_points; i++) {
00497         en_to_xy(points->x[i], points->y[i], &x, &y);
00498         robj->point[i].x = x;
00499         robj->point[i].y = y;
00500     }
00501 }