#include #include #include #include #include #include #include #include "local_proto.h" int plot_grid (double grid_size, double east, double north, int do_text) { double x,y; double e1,e2; struct Cell_head window ; double row_dist, colm_dist; char text[128]; int fontsize = 9; G_get_set_window (&window); /* pull right and bottom edges back one pixel; display lib bug? */ row_dist = D_d_to_u_row(0.) - D_d_to_u_row(1.); colm_dist = D_d_to_u_col(1.) - D_d_to_u_col(0.); window.south = window.south + row_dist; window.east = window.east - colm_dist; G_setup_plot ( D_get_d_north(), D_get_d_south(), D_get_d_west(), D_get_d_east(), D_move_abs, D_cont_abs); /* Draw vertical grids */ if (window.west > east) x = ceil((window.west - east)/grid_size) * grid_size + east ; else x = east - ceil((east - window.west)/grid_size) * grid_size ; while (x <= window.east) { G_plot_line (x, window.north, x, window.south); if(do_text) { G_format_easting(x, text, G_projection()); R_text_rotation(270.0); R_text_size(fontsize, fontsize); /* Positioning - x: 4 pixels to the right of the grid line, + 0.5 rounding factor. y: End of text is 7 pixels up from bottom of screen, +.5 rounding. fontsize*.81 = actual text width FOR DEFAULT FONT (NOT FreeType) */ R_move_abs((int)(D_u_to_d_col(x)+4 +.5), (int)(D_get_d_south() - (strlen(text)*fontsize*0.81) - 7 + 0.5)); R_text(text); } x += grid_size; } R_text_rotation(0.0); /* reset */ /* Draw horizontal grids * * For latlon, must draw in shorter sections * to make sure that each section of the grid * line is less than half way around the globe */ e1 = (window.east*2 + window.west)/3; e2 = (window.west*2 + window.east)/3; if (window.south > north) y = ceil((window.south - north)/grid_size) * grid_size + north ; else y = north - ceil((north - window.south)/grid_size) * grid_size ; while (y <= window.north) { G_plot_line (window.east, y, e1, y); G_plot_line (e1, y, e2, y); G_plot_line (e2, y, window.west, y); if(do_text) { G_format_northing(y, text, G_projection()); R_text_size(fontsize, fontsize); /* Positioning - x: End of text is 7 pixels left from right edge of screen, +.5 rounding. fontsize*.81 = actual text width FOR DEFAULT FONT (NOT FreeType) y: 4 pixels above each grid line, +.5 rounding. */ R_move_abs( (int)(D_get_d_east() - (strlen(text)*fontsize*0.81) - 7 + 0.5), (int)(D_u_to_d_row(y)-4 +.5) ); R_text(text); } y += grid_size; } return 0; } int plot_geogrid(double size, struct pj_info info_in, struct pj_info info_out, int do_text) { double g; double e1, e2, n1, n2; double east, west, north, south; double start_coord; double lat, lon; int j, ll; int SEGS=100; char text[128]; int fontsize = 9; float border_off = 4.5; float grid_off = 3.; double row_dist, colm_dist; float font_angle; struct Cell_head window ; /* geo current region */ G_get_set_window (&window); /* Adjust south and east back by one pixel for display bug? */ row_dist = D_d_to_u_row(0.) - D_d_to_u_row(1.); colm_dist = D_d_to_u_col(1.) - D_d_to_u_col(0.); window.south += row_dist; window.east -= colm_dist; /* get lat long min max */ /* probably need something like boardwalk ?? */ get_ll_bounds(&west, &east, &south, &north, window, info_in, info_out); G_debug(3, "REGION BOUNDS N=%f S=%f E=%f W=%f", north, south, east, west); G_setup_plot (D_get_d_north(), D_get_d_south(), D_get_d_west(), D_get_d_east(), D_move_abs, D_cont_abs); /* Lines of Latitude */ g = floor(north / size) * size ; e1 = east; for (j = 0; g >= south; j++, g -= size) { start_coord = -9999.; if (g == north || g == south) continue; for (ll = 0; ll < SEGS; ll++) { n1 = n2 = g; e1 = west + (ll *((east - west)/SEGS)); e2 = e1 + ((east - west)/SEGS); if (pj_do_proj(&e1, &n1, &info_in, &info_out) <0) G_fatal_error( _("Error in pj_do_proj")); check_coords(e1, n1, &lon, &lat, 1, window, info_in, info_out); e1 = lon; n1 = lat; if (pj_do_proj(&e2, &n2, &info_in, &info_out) <0) G_fatal_error( _("Error in pj_do_proj")); check_coords(e2, n2, &lon, &lat, 1, window, info_in, info_out); e2 = lon; n2 = lat; if (start_coord == -9999.) { start_coord = n1; font_angle = get_heading( (e1-e2), (n1-n2) ); } G_plot_line(e1, n1, e2, n2); } if(do_text) { G_format_northing(g, text, PROJECTION_LL); R_text_rotation(font_angle); R_text_size(fontsize, fontsize); R_move_abs( (int)(D_get_d_west() + border_off), (int)(D_u_to_d_row(start_coord) - grid_off) ); R_text(text); } } /* Lines of Longitude */ g = floor (east / size) * size ; n1 = north; for (j = 0; g > west; j++, g -= size) { start_coord = -9999.; if (g == east || g == west) continue; for (ll = 0; ll < SEGS; ll++) { e1 = e2 = g; n1 = north - (ll *((north - south)/SEGS)); n2 = n1 - ((north - south)/SEGS); /* n1 = south + (ll *((north - south)/SEGS)); n2 = n1 + ((north - south)/SEGS); */ if (pj_do_proj(&e1, &n1, &info_in, &info_out) <0) G_fatal_error( _("Error in pj_do_proj")); check_coords(e1, n1, &lon, &lat, 2, window, info_in, info_out); e1 = lon; n1 = lat; if (pj_do_proj(&e2, &n2, &info_in, &info_out) <0) G_fatal_error( _("Error in pj_do_proj")); check_coords(e2, n2, &lon, &lat, 2, window, info_in, info_out); e2 = lon; n2 = lat; if (start_coord == -9999.) { font_angle = get_heading( (e1-e2), (n1-n2) ); start_coord = e1; } G_plot_line(e1, n1, e2, n2); } if(do_text) { G_format_easting(g, text, PROJECTION_LL); R_text_rotation(font_angle); R_text_size(fontsize, fontsize); R_move_abs((int)(D_u_to_d_col(start_coord) + grid_off + 1.5), (int)(D_get_d_north() + border_off)); R_text(text); } } R_text_rotation(0.0); /* reset */ return 0; } /****************************************************** * initialze projection stuff and return proj structures ********************************************************/ void init_proj(struct pj_info *info_in, struct pj_info *info_out, int wgs84) { struct Key_Value *out_proj_keys, *out_unit_keys; /* Proj stuff for geo grid */ /* Out Info */ out_proj_keys = G_get_projinfo(); out_unit_keys = G_get_projunits(); if (pj_get_kv(info_out,out_proj_keys,out_unit_keys) < 0) G_fatal_error( _("Can't get projection key values of current location")); /* In Info */ if(!wgs84) { /* Set lat/long to same ellipsoid as location if we're not looking * for the WGS84 values */ if (GPJ_get_equivalent_latlong(info_in, info_out) < 0) G_fatal_error(_("Unable to set up lat/long projection parameters")); } else { struct Key_Value *in_proj_info, *in_unit_info; char buff[100], dum[100]; in_proj_info = G_create_key_value(); in_unit_info = G_create_key_value(); /* Check that datumparams are defined for this location (otherwise * the WGS84 values would be meaningless), and if they are set the * input datum to WGS84 */ if( G_get_datumparams_from_projinfo(out_proj_keys, buff, dum) < 0 ) G_fatal_error(_("WGS84 grid output not possible as this location does not contain\n" "datum transformation parameters. Try running g.setproj.")); else G_set_key_value("datum", "wgs84", in_proj_info); /* set input projection to lat/long */ G_set_key_value("proj", "ll", in_proj_info); G_set_key_value("unit", "degree", in_unit_info); G_set_key_value("units", "degrees", in_unit_info); G_set_key_value("meters", "1.0", in_unit_info); if (pj_get_kv(info_in, in_proj_info, in_unit_info) < 0) G_fatal_error(_("Unable to set up lat/long projection parameters")); G_free_key_value( in_proj_info ); G_free_key_value( in_unit_info ); } G_free_key_value( out_proj_keys); G_free_key_value( out_unit_keys); return; } /****************************************************** * Use Proj to get min max bounds of region in lat long ********************************************************/ void get_ll_bounds( double *w, double *e, double *s, double *n, struct Cell_head window, struct pj_info info_in, struct pj_info info_out) { double east, west, north, south; double e1, w1, n1, s1; double ew, ns; double ew_res, ns_res; int first; *w = *e = *n = *s = -999.; west = east = north = south = -999.; e1 = window.east; w1 = window.west; n1 = window.north; s1 = window.south; /* calculate resolution based upon 100 rows/cols * to prevent possible time consuming parsing in large regions */ ew_res = (e1-w1)/100.; ns_res = (n1-s1)/100.; /* Get geographic min max from ala boardwalk style */ /* North */ first = 0; for (ew = window.west; ew <= window.east; ew+=ew_res) { e1 = ew; n1 = window.north; if (pj_do_proj(&e1, &n1, &info_out, &info_in) <0) G_fatal_error( _("Error in pj_do_proj")); if (!first) { north = n1; first = 1; } else { if (n1 > north) north = n1; } } /*South*/ first = 0; for (ew = window.west; ew <= window.east; ew+=ew_res) { e1 = ew; s1 = window.south; if (pj_do_proj(&e1, &s1, &info_out, &info_in) <0) G_fatal_error( _("Error in pj_do_proj")); if (!first) { south = s1; first = 1; } else { if (s1 < south) south = s1; } } /*East*/ first = 0; for (ns = window.south; ns <= window.north; ns+=ns_res) { e1 = window.east; n1 = ns; if (pj_do_proj(&e1, &n1, &info_out, &info_in) <0) G_fatal_error( _("Error in pj_do_proj")); if (!first) { east = e1; first = 1; } else { if (e1 > east) east = e1; } } /*West*/ first = 0; for (ns = window.south; ns <= window.north; ns+=ns_res) { w1 = window.west; n1 = ns; if (pj_do_proj(&w1, &n1, &info_out, &info_in) <0) G_fatal_error( _("Error in pj_do_proj")); if (!first) { west = w1; first = 1; } else { if (w1 < west) west = w1; } } *w = west; *e = east; *s = south; *n = north; return; } /****************************************************** * check projected coords to make sure they do not * go outside region -- if so re-project ********************************************************/ void check_coords( double e, double n, double *lon, double *lat, int par, struct Cell_head w, struct pj_info info_in, struct pj_info info_out) { double x, y; int proj = 0; *lat = y = n; *lon = x = e; if (e < w.west) { x = w.west; proj = 1; } if (e > w.east) { x = w.east; proj = 1; } if(n < w.south) { y = w.south; proj = 1; } if (n > w.north) { y = w.north; proj = 1; } if (proj) { /* convert original coords to ll */ if (pj_do_proj(&e, &n, &info_out, &info_in) <0) G_fatal_error( _("Error in pj_do_proj1")); if (par == 1) { /* lines of latitude -- const. northing */ /* convert correct UTM to ll */ if (pj_do_proj(&x, &y, &info_out, &info_in) <0) G_fatal_error( _("Error in pj_do_proj2")); /* convert new ll back to coords */ if (pj_do_proj(&x, &n, &info_in, &info_out) <0) G_fatal_error( _("Error in pj_do_proj3")); *lat = n; *lon = x; } if (par == 2) { /* lines of longitude -- const. easting */ /* convert correct UTM to ll */ if (pj_do_proj(&x, &y, &info_out, &info_in) <0) G_fatal_error( _("Error in pj_do_proj5")); /* convert new ll back to coords */ if (pj_do_proj(&e, &y, &info_in, &info_out) <0) G_fatal_error( _("Error in pj_do_proj6")); *lat = y; *lon = e; } } return; } /******************************************* * function to calculate azimuth in degrees * from rows and columns *******************************************/ float get_heading(double rows, double cols) { float azi; /* NE Quad or due south */ if (rows < 0 && cols <= 0) { azi = RAD_TO_DEG*atan((cols/rows)); if (azi < 0.) azi *= -1.; } /* SE Quad or due east */ if (rows >= 0 && cols < 0) { azi = RAD_TO_DEG*atan((rows/cols)); if (azi < 0.) azi *= -1.; azi = 90. + azi; } /* SW Quad or due south */ if (rows > 0 && cols >= 0) { azi = RAD_TO_DEG*atan((rows/cols)); if (azi < 0.) azi *= -1.; azi = 270. - azi; } /* NW Quad or due south */ if (rows <= 0 && cols > 0) { azi = RAD_TO_DEG*atan((rows/cols)); if (azi < 0.) azi *= -1.; azi = 270. + azi; } return (azi); }