123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- /***************************************************************************
- *
- * MODULE: r.proj
- *
- * AUTHOR(S): Martin Schroeder
- * University of Heidelberg
- * Dept. of Geography
- * emes@geo0.geog.uni-heidelberg.de
- *
- * (With the help of a lot of existing GRASS sources, in
- * particular v.proj)
- *
- * PURPOSE: r.proj converts a map to a new geographic projection. It reads a
- * map from a different location, projects it and write it out
- * to the current location. The projected data is resampled with
- * one of three different methods: nearest neighbor, bilinear and
- * cubic convolution.
- *
- * COPYRIGHT: (C) 2001 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.
- *
- * Changes
- * Morten Hulden <morten@ngb.se>, Aug 2000:
- * - aborts if input map is outside current location.
- * - can handle projections (conic, azimuthal etc) where
- * part of the map may fall into areas where south is
- * upward and east is leftward.
- * - avoids passing location edge coordinates to PROJ
- * (they may be invalid in some projections).
- * - output map will be clipped to borders of the current region.
- * - output map cell edges and centers will coinside with those
- * of the current region.
- * - output map resolution (unless changed explicitly) will
- * match (exactly) the resolution of the current region.
- * - if the input map is smaller than the current region, the
- * output map will only cover the overlapping area.
- * - if the input map is larger than the current region, only the
- * needed amount of memory will be allocated for the projection
- *
- * Bugfixes 20050328: added floor() before (int) typecasts to in avoid
- * assymetrical rounding errors. Added missing offset outcellhd.ew_res/2
- * to initial xcoord for each row in main projection loop (we want to project
- * center of cell, not border).
- *****************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <grass/gis.h>
- #include <grass/gprojects.h>
- #include <grass/glocale.h>
- #include "r.proj.h"
- /* modify this table to add new methods */
- struct menu menu[] = {
- {p_nearest, "nearest", "nearest neighbor"},
- {p_bilinear, "bilinear", "bilinear"},
- {p_cubic, "cubic", "cubic convolution"},
- {NULL, NULL, NULL}
- };
- static char *make_ipol_list(void);
- int main(int argc, char **argv)
- {
- char *mapname, /* ptr to name of output layer */
- *setname, /* ptr to name of input mapset */
- *ipolname; /* name of interpolation method */
- int fdi, /* input map file descriptor */
- fdo, /* output map file descriptor */
- method, /* position of method in table */
- permissions, /* mapset permissions */
- cell_type, /* output celltype */
- cell_size, /* size of a cell in bytes */
- row, col, /* counters */
- irows, icols, /* original rows, cols */
- orows, ocols, have_colors, /* Input map has a colour table */
- overwrite; /* overwrite output map */
- void *obuffer, /* buffer that holds one output row */
- *obufptr; /* column ptr in output buffer */
- FCELL **ibuffer; /* buffer that holds the input map */
- func interpolate; /* interpolation routine */
- double xcoord1, xcoord2, /* temporary x coordinates */
- ycoord1, ycoord2, /* temporary y coordinates */
- col_idx, /* column index in input matrix */
- row_idx, /* row index in input matrix */
- onorth, osouth, /* save original border coords */
- oeast, owest, inorth, isouth, ieast, iwest;
- struct Colors colr; /* Input map colour table */
- struct History history;
- struct pj_info iproj, /* input map proj parameters */
- oproj; /* output map proj parameters */
- struct Key_Value *in_proj_info, /* projection information of */
- *in_unit_info, /* input and output mapsets */
- *out_proj_info, *out_unit_info;
- struct GModule *module;
- struct Flag *list, /* list files in source location */
- *nocrop; /* don't crop output map */
- struct Option *imapset, /* name of input mapset */
- *inmap, /* name of input layer */
- *inlocation, /* name of input location */
- *outmap, /* name of output layer */
- *indbase, /* name of input database */
- *interpol, /* interpolation method:
- nearest neighbor, bilinear, cubic */
- *res; /* resolution of target map */
- struct Cell_head incellhd, /* cell header of input map */
- outcellhd; /* and output map */
- G_gisinit(argv[0]);
- module = G_define_module();
- module->keywords = _("raster, projection");
- module->description =
- _("Re-projects a raster map from one location to the current location.");
- inmap = G_define_standard_option(G_OPT_R_INPUT);
- inmap->description = _("Name of input raster map to re-project");
- inmap->required = NO;
- inlocation = G_define_option();
- inlocation->key = "location";
- inlocation->type = TYPE_STRING;
- inlocation->required = YES;
- inlocation->description = _("Location of input raster map");
- imapset = G_define_option();
- imapset->key = "mapset";
- imapset->type = TYPE_STRING;
- imapset->required = NO;
- imapset->description = _("Mapset of input raster map");
- indbase = G_define_option();
- indbase->key = "dbase";
- indbase->type = TYPE_STRING;
- indbase->required = NO;
- indbase->description = _("Path to GRASS database of input location");
- outmap = G_define_standard_option(G_OPT_R_OUTPUT);
- outmap->required = NO;
- outmap->description = _("Name for output raster map (default: input)");
- ipolname = make_ipol_list();
- interpol = G_define_option();
- interpol->key = "method";
- interpol->type = TYPE_STRING;
- interpol->required = NO;
- interpol->answer = "nearest";
- interpol->options = ipolname;
- interpol->description = _("Interpolation method to use");
- res = G_define_option();
- res->key = "resolution";
- res->type = TYPE_DOUBLE;
- res->required = NO;
- res->description = _("Resolution of output map");
- list = G_define_flag();
- list->key = 'l';
- list->description = _("List raster maps in input location and exit");
- nocrop = G_define_flag();
- nocrop->key = 'n';
- nocrop->description = _("Do not perform region cropping optimization");
- /* The parser checks if the map already exists in current mapset,
- we switch out the check and do it
- * in the module after the parser */
- overwrite = G_check_overwrite(argc, argv);
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- /* get the method */
- for (method = 0; (ipolname = menu[method].name); method++)
- if (strcmp(ipolname, interpol->answer) == 0)
- break;
- if (!ipolname)
- G_fatal_error(_("<%s=%s> unknown %s"),
- interpol->key, interpol->answer, interpol->key);
- interpolate = menu[method].method;
- mapname = outmap->answer ? outmap->answer : inmap->answer;
- if (mapname && !list->answer && !overwrite &&
- G_find_cell(mapname, G_mapset()))
- G_fatal_error(_("option <%s>: <%s> exists."), "output", mapname);
- setname = imapset->answer ? imapset->answer : G_store(G_mapset());
- if (!indbase->answer && strcmp(inlocation->answer, G_location()) == 0)
- G_fatal_error(_("Input and output locations can not be the same"));
- G_get_window(&outcellhd);
- /* Get projection info for output mapset */
- if ((out_proj_info = G_get_projinfo()) == NULL)
- G_fatal_error(_("Unable to get projection info of output raster map"));
- if ((out_unit_info = G_get_projunits()) == NULL)
- G_fatal_error(_("Unable to get projection units of output raster map"));
- if (pj_get_kv(&oproj, out_proj_info, out_unit_info) < 0)
- G_fatal_error(_("Unable to get projection key values of output raster map"));
- /* Change the location */
- G__create_alt_env();
- G__setenv("GISDBASE", indbase->answer ? indbase->answer : G_gisdbase());
- G__setenv("LOCATION_NAME", inlocation->answer);
- permissions = G__mapset_permissions(setname);
- if (permissions < 0) /* can't access mapset */
- G_fatal_error(_("Mapset <%s> in input location <%s> - %s"),
- setname, inlocation->answer,
- permissions == 0 ? _("permission denied")
- : _("not found"));
- /* if requested, list the raster maps in source location - MN 5/2001 */
- if (list->answer) {
- if (isatty(0)) /* check if on command line */
- G_message(_("Checking location <%s>, mapset <%s>..."),
- inlocation->answer, setname);
- G_list_element("cell", "raster", setname, 0);
- exit(EXIT_SUCCESS); /* leave r.proj after listing */
- }
- if (!inmap->answer)
- G_fatal_error(_("Required parameter <%s> not set"), inmap->key);
- if (!G_find_cell(inmap->answer, setname))
- G_fatal_error(_("Raster map <%s> in location <%s> in mapset <%s> not found"),
- inmap->answer, inlocation->answer, setname);
- /* Read input map colour table */
- have_colors = G_read_colors(inmap->answer, setname, &colr);
- /* Get projection info for input mapset */
- if ((in_proj_info = G_get_projinfo()) == NULL)
- G_fatal_error(_("Unable to get projection info of input map"));
- if ((in_unit_info = G_get_projunits()) == NULL)
- G_fatal_error(_("Unable to get projection units of input map"));
- if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0)
- G_fatal_error(_("Unable to get projection key values of input map"));
- G_free_key_value(in_proj_info);
- G_free_key_value(in_unit_info);
- G_free_key_value(out_proj_info);
- G_free_key_value(out_unit_info);
- pj_print_proj_params(&iproj, &oproj);
- /* this call causes r.proj to read the entire map into memeory */
- G_get_cellhd(inmap->answer, setname, &incellhd);
- G_set_window(&incellhd);
- if (G_projection() == PROJECTION_XY)
- G_fatal_error(_("Unable to work with unprojected data (xy location)"));
- /* Save default borders so we can show them later */
- inorth = incellhd.north;
- isouth = incellhd.south;
- ieast = incellhd.east;
- iwest = incellhd.west;
- irows = incellhd.rows;
- icols = incellhd.cols;
- onorth = outcellhd.north;
- osouth = outcellhd.south;
- oeast = outcellhd.east;
- owest = outcellhd.west;
- orows = outcellhd.rows;
- ocols = outcellhd.cols;
- /* Cut non-overlapping parts of input map */
- if (!nocrop->answer)
- bordwalk(&outcellhd, &incellhd, &oproj, &iproj);
- /* Add 2 cells on each side for bilinear/cubic & future interpolation methods */
- /* (should probably be a factor based on input and output resolution) */
- incellhd.north += 2 * incellhd.ns_res;
- incellhd.east += 2 * incellhd.ew_res;
- incellhd.south -= 2 * incellhd.ns_res;
- incellhd.west -= 2 * incellhd.ew_res;
- if (incellhd.north > inorth)
- incellhd.north = inorth;
- if (incellhd.east > ieast)
- incellhd.east = ieast;
- if (incellhd.south < isouth)
- incellhd.south = isouth;
- if (incellhd.west < iwest)
- incellhd.west = iwest;
- G_set_window(&incellhd);
- /* And switch back to original location */
- G__switch_env();
- /* Adjust borders of output map */
- if (!nocrop->answer)
- bordwalk(&incellhd, &outcellhd, &iproj, &oproj);
- #if 0
- outcellhd.west = outcellhd.south = HUGE_VAL;
- outcellhd.east = outcellhd.north = -HUGE_VAL;
- for (row = 0; row < incellhd.rows; row++) {
- ycoord1 = G_row_to_northing((double)(row + 0.5), &incellhd);
- for (col = 0; col < incellhd.cols; col++) {
- xcoord1 = G_col_to_easting((double)(col + 0.5), &incellhd);
- pj_do_proj(&xcoord1, &ycoord1, &iproj, &oproj);
- if (xcoord1 > outcellhd.east)
- outcellhd.east = xcoord1;
- if (ycoord1 > outcellhd.north)
- outcellhd.north = ycoord1;
- if (xcoord1 < outcellhd.west)
- outcellhd.west = xcoord1;
- if (ycoord1 < outcellhd.south)
- outcellhd.south = ycoord1;
- }
- }
- #endif
- if (res->answer != NULL) /* set user defined resolution */
- outcellhd.ns_res = outcellhd.ew_res = atof(res->answer);
- G_adjust_Cell_head(&outcellhd, 0, 0);
- G_set_window(&outcellhd);
- G_message(NULL);
- G_message(_("Input:"));
- G_message(_("Cols: %d (%d)"), incellhd.cols, icols);
- G_message(_("Rows: %d (%d)"), incellhd.rows, irows);
- G_message(_("North: %f (%f)"), incellhd.north, inorth);
- G_message(_("South: %f (%f)"), incellhd.south, isouth);
- G_message(_("West: %f (%f)"), incellhd.west, iwest);
- G_message(_("East: %f (%f)"), incellhd.east, ieast);
- G_message(_("EW-res: %f"), incellhd.ew_res);
- G_message(_("NS-res: %f"), incellhd.ns_res);
- G_message(NULL);
- G_message(_("Output:"));
- G_message(_("Cols: %d (%d)"), outcellhd.cols, ocols);
- G_message(_("Rows: %d (%d)"), outcellhd.rows, orows);
- G_message(_("North: %f (%f)"), outcellhd.north, onorth);
- G_message(_("South: %f (%f)"), outcellhd.south, osouth);
- G_message(_("West: %f (%f)"), outcellhd.west, owest);
- G_message(_("East: %f (%f)"), outcellhd.east, oeast);
- G_message(_("EW-res: %f"), outcellhd.ew_res);
- G_message(_("NS-res: %f"), outcellhd.ns_res);
- G_message(NULL);
- /* open and read the relevant parts of the input map and close it */
- G__switch_env();
- G_set_window(&incellhd);
- fdi = G_open_cell_old(inmap->answer, setname);
- cell_type = G_get_raster_map_type(fdi);
- ibuffer = (FCELL **) readcell(fdi);
- G_close_cell(fdi);
- G__switch_env();
- G_set_window(&outcellhd);
- if (strcmp(interpol->answer, "nearest") == 0) {
- fdo = G_open_raster_new(mapname, cell_type);
- obuffer = (CELL *) G_allocate_raster_buf(cell_type);
- }
- else {
- fdo = G_open_fp_cell_new(mapname);
- cell_type = FCELL_TYPE;
- obuffer = (FCELL *) G_allocate_raster_buf(cell_type);
- }
- cell_size = G_raster_size(cell_type);
- xcoord1 = xcoord2 = outcellhd.west + (outcellhd.ew_res / 2);
- /**/ ycoord1 = ycoord2 = outcellhd.north - (outcellhd.ns_res / 2);
- /**/ G_important_message(_("Projecting..."));
- G_percent(0, outcellhd.rows, 2);
- for (row = 0; row < outcellhd.rows; row++) {
- obufptr = obuffer;
- for (col = 0; col < outcellhd.cols; col++) {
- /* project coordinates in output matrix to */
- /* coordinates in input matrix */
- if (pj_do_proj(&xcoord1, &ycoord1, &oproj, &iproj) < 0)
- G_set_null_value(obufptr, 1, cell_type);
- else {
- /* convert to row/column indices of input matrix */
- col_idx = (xcoord1 - incellhd.west) / incellhd.ew_res;
- row_idx = (incellhd.north - ycoord1) / incellhd.ns_res;
- /* and resample data point */
- interpolate(ibuffer, obufptr, cell_type,
- &col_idx, &row_idx, &incellhd);
- }
- obufptr = G_incr_void_ptr(obufptr, cell_size);
- xcoord2 += outcellhd.ew_res;
- xcoord1 = xcoord2;
- ycoord1 = ycoord2;
- }
- if (G_put_raster_row(fdo, obuffer, cell_type) < 0)
- G_fatal_error(_("Failed writing raster map <%s> row %d"), mapname,
- row);
- xcoord1 = xcoord2 = outcellhd.west + (outcellhd.ew_res / 2);
- ycoord2 -= outcellhd.ns_res;
- ycoord1 = ycoord2;
- G_percent(row, outcellhd.rows - 1, 2);
- }
- G_close_cell(fdo);
- if (have_colors > 0) {
- G_write_colors(mapname, G_mapset(), &colr);
- G_free_colors(&colr);
- }
- G_short_history(mapname, "raster", &history);
- G_command_history(&history);
- G_write_history(mapname, &history);
- G_done_msg(" ");
- exit(EXIT_SUCCESS);
- }
- static char *make_ipol_list(void)
- {
- int size = 0;
- int i;
- char *buf;
- for (i = 0; menu[i].name; i++)
- size += strlen(menu[i].name) + 1;
- buf = G_malloc(size);
- *buf = '\0';
- for (i = 0; menu[i].name; i++) {
- if (i)
- strcat(buf, ",");
- strcat(buf, menu[i].name);
- }
- return buf;
- }
|