GRASS Programmer's Manual
6.4.2(2012)
|
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 }