123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269 |
- /****************************************************************************
- *
- * MODULE: r.cost
- *
- * AUTHOR(S): Antony Awaida - IESL - M.I.T.
- * James Westervelt - CERL
- * Pierre de Mouveaux <pmx audiovu com>
- * Eric G. Miller <egm2 jps net>
- *
- * Updated for calculation errors and directional surface generation
- * Colin Nielsen <colin.nielsen gmail com>
- * Use min heap instead of btree (faster, less memory)
- * Markus Metz
- *
- * PURPOSE: Outputs a raster map layer showing the cumulative cost
- * of moving between different geographic locations on an
- * input raster map layer whose cell category values
- * represent cost.
- *
- * COPYRIGHT: (C) 2006-2009 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.
- *
- ***************************************************************************/
- /*********************************************************************
- *
- * This is the main program for the minimum path cost analysis.
- * It generates a cumulative cost map (output) from an elevation
- * or cost map (input) with respect to starting locations (coor).
- *
- * It takes as input the following:
- * 1) Cost of traversing each grid cell as given by a cost map
- * cell (input).
- * 2) If starting points are not specified on the command line
- * then the output map must exist and contain the starting locations
- *
- * Otherwise the output map need not exist and the coor points
- * from the command line are used.
- *
- *********************************************************************/
- /* BUG 2005: r.cost probably hangs with negative costs.
- * Positive costs could be a condition for Dijkstra search? MM
- *
- * 08 april 2000 - Pierre de Mouveaux. pmx@audiovu.com
- * Updated to use the Grass 5.0 floating point raster cell format.
- *
- * 12 dec 2001 - Eric G. Miller <egm2@jps.net>
- * Try to fix some file searching bugs, and give better error
- * if "output" doesn't exist, but is expected (this is bad design).
- */
- /* TODO
- * use Vect_*() functions
- * use search tree for stop points
- * re-organize and clean up code for better readability
- * compartmentalize code, start with putting Dijkstra search into a separate function
- */
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <math.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/vector.h>
- #include <grass/segment.h>
- #include <grass/glocale.h>
- #include "cost.h"
- #include "stash.h"
- #define SEGCOLSIZE 64
- struct Cell_head window;
- struct start_pt *head_start_pt = NULL;
- struct start_pt *head_end_pt = NULL;
- int main(int argc, char *argv[])
- {
- const char *cum_cost_layer, *move_dir_layer, *nearest_layer;
- const char *cost_layer;
- const char *cost_mapset, *search_mapset;
- void *cell, *cell2, *dir_cell, *nearest_cell;
- SEGMENT cost_seg, dir_seg;
- double *value;
- extern struct Cell_head window;
- double NS_fac, EW_fac, DIAG_fac, H_DIAG_fac, V_DIAG_fac;
- double fcost;
- double min_cost, old_min_cost;
- FCELL cur_dir;
- double zero = 0.0;
- int col, row, nrows, ncols;
- int maxcost;
- int nseg;
- int maxmem;
- int segments_in_memory;
- int cost_fd, cum_fd, dir_fd, nearest_fd;
- int have_stop_points = FALSE, dir = FALSE;
- double my_cost, nearest;
- double null_cost, dnullval;
- int srows, scols;
- int total_reviewed;
- int keep_nulls = 1;
- int start_with_raster_vals = 1;
- int neighbor;
- long n_processed = 0;
- long total_cells;
- struct GModule *module;
- struct Flag *flag2, *flag3, *flag4, *flag5;
- struct Option *opt1, *opt2, *opt3, *opt4, *opt5, *opt6, *opt7, *opt8;
- struct Option *opt9, *opt10, *opt11, *opt12;
- struct cost *pres_cell;
- struct start_pt *pres_start_pt = NULL;
- struct start_pt *pres_stop_pt = NULL;
- struct cc {
- double cost_in, cost_out, nearest;
- } costs;
- void *ptr2;
- RASTER_MAP_TYPE data_type, /* input cost type */
- cum_data_type = DCELL_TYPE, /* output cumulative cost type */
- dir_data_type = FCELL_TYPE, /* output direction type */
- nearest_data_type = CELL_TYPE; /* output nearest type */
- struct History history;
- double peak = 0.0;
- int dsize, nearest_size;
- double disk_mb, mem_mb;
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("raster"));
- G_add_keyword(_("cost surface"));
- G_add_keyword(_("cumulative costs"));
- G_add_keyword(_("cost allocation"));
- module->description =
- _("Creates a raster map showing the "
- "cumulative cost of moving between different "
- "geographic locations on an input raster map "
- "whose cell category values represent cost.");
- opt2 = G_define_standard_option(G_OPT_R_INPUT);
- opt2->description =
- _("Name of input raster map containing grid cell cost information");
- opt1 = G_define_standard_option(G_OPT_R_OUTPUT);
- opt12 = G_define_standard_option(G_OPT_R_OUTPUT);
- opt12->key = "nearest";
- opt12->required = NO;
- opt12->description =
- _("Name for output raster map with nearest start point");
- opt12->guisection = _("Optional outputs");
- opt11 = G_define_standard_option(G_OPT_R_OUTPUT);
- opt11->key = "outdir";
- opt11->required = NO;
- opt11->description =
- _("Name for output raster map to contain movement directions");
- opt11->guisection = _("Optional outputs");
- opt7 = G_define_standard_option(G_OPT_V_INPUT);
- opt7->key = "start_points";
- opt7->required = NO;
- opt7->label = _("Name of starting vector points map");
- opt7->guisection = _("Start");
- opt8 = G_define_standard_option(G_OPT_V_INPUT);
- opt8->key = "stop_points";
- opt8->required = NO;
- opt8->label = _("Name of stopping vector points map");
- opt8->guisection = _("Stop");
- opt9 = G_define_standard_option(G_OPT_R_INPUT);
- opt9->key = "start_raster";
- opt9->required = NO;
- opt9->description = _("Name of starting raster points map");
- opt9->guisection = _("Start");
- opt3 = G_define_standard_option(G_OPT_M_COORDS);
- opt3->key = "start_coordinates";
- opt3->multiple = YES;
- opt3->description =
- _("Coordinates of starting point(s) (E,N)");
- opt3->guisection = _("Start");
- opt4 = G_define_standard_option(G_OPT_M_COORDS);
- opt4->key = "stop_coordinates";
- opt4->multiple = YES;
- opt4->description =
- _("Coordinates of stopping point(s) (E,N)");
- opt4->guisection = _("Stop");
- opt5 = G_define_option();
- opt5->key = "max_cost";
- opt5->type = TYPE_INTEGER;
- opt5->key_desc = "value";
- opt5->required = NO;
- opt5->multiple = NO;
- opt5->answer = "0";
- opt5->description = _("Maximum cumulative cost");
- opt6 = G_define_option();
- opt6->key = "null_cost";
- opt6->type = TYPE_DOUBLE;
- opt6->key_desc = "value";
- opt6->required = NO;
- opt6->multiple = NO;
- opt6->description =
- _("Cost assigned to null cells. By default, null cells are excluded");
- opt6->guisection = _("NULL cells");
- opt10 = G_define_option();
- opt10->key = "percent_memory";
- opt10->type = TYPE_INTEGER;
- opt10->key_desc = "value";
- opt10->required = NO;
- opt10->multiple = NO;
- opt10->answer = "40";
- opt10->options = "0-100";
- opt10->description = _("Percent of map to keep in memory");
- flag2 = G_define_flag();
- flag2->key = 'k';
- flag2->description =
- _("Use the 'Knight's move'; slower, but more accurate");
- flag3 = G_define_flag();
- flag3->key = 'n';
- flag3->description = _("Keep null values in output raster map");
- flag3->guisection = _("NULL cells");
- flag4 = G_define_flag();
- flag4->key = 'r';
- flag4->description = _("Start with values in raster map");
- flag4->guisection = _("Start");
- flag5 = G_define_flag();
- flag5->key = 'i';
- flag5->description = _("Print info about disk space and memory requirements and exit");
- /* Parse options */
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- /* If no outdir is specified, set flag to skip all dir */
- if (opt11->answer != NULL)
- dir = 1;
- /* Get database window parameters */
- Rast_get_window(&window);
- /* Find north-south, east_west and diagonal factors */
- EW_fac = 1.0;
- NS_fac = window.ns_res / window.ew_res;
- DIAG_fac = (double)sqrt((double)(NS_fac * NS_fac + EW_fac * EW_fac));
- V_DIAG_fac =
- (double)sqrt((double)(4 * NS_fac * NS_fac + EW_fac * EW_fac));
- H_DIAG_fac =
- (double)sqrt((double)(NS_fac * NS_fac + 4 * EW_fac * EW_fac));
- EW_fac /= 2.0;
- NS_fac /= 2.0;
- DIAG_fac /= 2.0;
- V_DIAG_fac /= 4.0;
- H_DIAG_fac /= 4.0;
- Rast_set_d_null_value(&null_cost, 1);
- if (flag2->answer)
- total_reviewed = 16;
- else
- total_reviewed = 8;
- keep_nulls = flag3->answer;
- start_with_raster_vals = flag4->answer;
- {
- int count = 0;
- if (opt3->answers)
- count++;
- if (opt7->answers)
- count++;
- if (opt9->answers)
- count++;
- if (count != 1)
- G_fatal_error(_("Must specify exactly one of start_points, start_rast or coordinate"));
- }
- if (opt3->answers)
- if (!process_answers(opt3->answers, &head_start_pt, &pres_start_pt))
- G_fatal_error(_("No start points"));
- if (opt4->answers)
- have_stop_points =
- process_answers(opt4->answers, &head_end_pt, &pres_stop_pt);
- if (sscanf(opt5->answer, "%d", &maxcost) != 1 || maxcost < 0)
- G_fatal_error(_("Inappropriate maximum cost: %d"), maxcost);
- if (sscanf(opt10->answer, "%d", &maxmem) != 1 || maxmem < 0 ||
- maxmem > 100)
- G_fatal_error(_("Inappropriate percent memory: %d"), maxmem);
- if ((opt6->answer == NULL) ||
- (sscanf(opt6->answer, "%lf", &null_cost) != 1)) {
- G_debug(1, "Null cells excluded from cost evaluation");
- Rast_set_d_null_value(&null_cost, 1);
- }
- else if (keep_nulls)
- G_debug(1,"Input null cell will be retained into output map");
- if (opt7->answer) {
- search_mapset = G_find_vector2(opt7->answer, "");
- if (search_mapset == NULL)
- G_fatal_error(_("Vector map <%s> not found"), opt7->answer);
- }
- if (!Rast_is_d_null_value(&null_cost)) {
- if (null_cost < 0.0) {
- G_warning(_("Assigning negative cost to null cell. Null cells excluded."));
- Rast_set_d_null_value(&null_cost, 1);
- }
- }
- else {
- keep_nulls = 0; /* handled automagically... */
- }
- cum_cost_layer = opt1->answer;
- cost_layer = opt2->answer;
- move_dir_layer = opt11->answer;
- nearest_layer = opt12->answer;
- /* Find number of rows and columns in window */
- nrows = Rast_window_rows();
- ncols = Rast_window_cols();
- /* Open cost cell layer for reading */
- cost_mapset = G_find_raster2(cost_layer, "");
- if (cost_mapset == NULL)
- G_fatal_error(_("Raster map <%s> not found"), cost_layer);
- cost_fd = Rast_open_old(cost_layer, cost_mapset);
- data_type = Rast_get_map_type(cost_fd);
- /* Parameters for map submatrices */
- switch (data_type) {
- case (CELL_TYPE):
- G_debug(1, "Source map is: Integer cell type");
- break;
- case (FCELL_TYPE):
- G_debug(1, "Source map is: Floating point (float) cell type");
- break;
- case (DCELL_TYPE):
- G_debug(1, "Source map is: Floating point (double) cell type");
- break;
- }
- G_debug(1, " %d rows, %d cols", nrows, ncols);
- /* this is most probably the limitation of r.cost for large datasets
- * segment size needs to be reduced to avoid unecessary disk IO
- * but it doesn't make sense to go down to 1
- * so use 64 segment rows and cols for <= 200 million cells
- * for larger regions, 32 segment rows and cols
- * maybe go down to 16 for > 500 million cells ? */
- if ((double) nrows * ncols > 200000000)
- srows = scols = SEGCOLSIZE / 2;
- else
- srows = scols = SEGCOLSIZE;
- if (maxmem == 100) {
- srows = scols = 256;
- }
- /* calculate total number of segments */
- nseg = ((nrows + srows - 1) / srows) * ((ncols + scols - 1) / scols);
- if (maxmem > 0)
- segments_in_memory = (maxmem * nseg) / 100;
- /* maxmem = 0 */
- else
- segments_in_memory = 4 * (nrows / srows + ncols / scols + 2);
- if (segments_in_memory == 0)
- segments_in_memory = 1;
- /* report disk space and memory requirements */
- if (dir == TRUE) {
- disk_mb = (double) nrows * ncols * 28. / 1048576.;
- mem_mb = (double) srows * scols * 28. / 1048576. * segments_in_memory;
- mem_mb += nrows * ncols * 0.05 * 20. / 1048576.; /* for Dijkstra search */
- }
- else {
- disk_mb = (double) nrows * ncols * 24. / 1048576.;
- mem_mb = (double) srows * scols * 24. / 1048576. * segments_in_memory;
- mem_mb += nrows * ncols * 0.05 * 20. / 1048576.; /* for Dijkstra search */
- }
- if (flag5->answer) {
- fprintf(stdout, _("Will need at least %.2f MB of disk space"), disk_mb);
- fprintf(stdout, "\n");
- fprintf(stdout, _("Will need at least %.2f MB of memory"), mem_mb);
- fprintf(stdout, "\n");
- Rast_close(cost_fd);
- exit(EXIT_SUCCESS);
- }
- G_verbose_message("--------------------------------------------");
- G_verbose_message(_("Will need at least %.2f MB of disk space"), disk_mb);
- G_verbose_message(_("Will need at least %.2f MB of memory"), mem_mb);
- G_verbose_message("--------------------------------------------");
- /* Create segmented format files for cost layer and output layer */
- G_verbose_message(_("Creating some temporary files..."));
- if (Segment_open(&cost_seg, G_tempfile(), nrows, ncols, srows, scols,
- sizeof(struct cc), segments_in_memory) != 1)
- G_fatal_error(_("Can not create temporary file"));
- if (dir == TRUE) {
- if (Segment_open(&dir_seg, G_tempfile(), nrows, ncols, srows, scols,
- sizeof(FCELL), segments_in_memory) != 1)
- G_fatal_error(_("Can not create temporary file"));
- }
- /* Write the cost layer in the segmented file */
- G_message(_("Reading raster map <%s>, initializing output..."),
- G_fully_qualified_name(cost_layer, cost_mapset));
- {
- int i, skip_nulls;
- double p;
- Rast_set_d_null_value(&dnullval, 1);
- costs.cost_out = dnullval;
- costs.nearest = 0;
- total_cells = nrows * ncols;
- skip_nulls = Rast_is_d_null_value(&null_cost);
- dsize = Rast_cell_size(data_type);
- cell = Rast_allocate_buf(data_type);
- p = 0.0;
- for (row = 0; row < nrows; row++) {
- G_percent(row, nrows, 2);
- Rast_get_row(cost_fd, cell, row, data_type);
- /* INPUT NULL VALUES: ??? */
- ptr2 = cell;
- for (i = 0; i < ncols; i++) {
- if (Rast_is_null_value(ptr2, data_type)) {
- p = null_cost;
- if (skip_nulls) {
- total_cells--;
- }
- }
- else {
- switch (data_type) {
- case CELL_TYPE:
- p = *(CELL *)ptr2;
- break;
- case FCELL_TYPE:
- p = *(FCELL *)ptr2;
- break;
- case DCELL_TYPE:
- p = *(DCELL *)ptr2;
- break;
- }
- }
- if (p < 0) {
- G_warning(_("Negative cell value found at row %d, col %d. "
- "Setting negative value to null_cost value"),
- row, i);
- p = null_cost;
- }
- costs.cost_in = p;
- Segment_put(&cost_seg, &costs, row, i);
- ptr2 = G_incr_void_ptr(ptr2, dsize);
- }
- }
- G_free(cell);
- G_percent(1, 1, 1);
- }
- if (dir == TRUE) {
- G_message(_("Initializing directional output..."));
- for (row = 0; row < nrows; row++) {
- G_percent(row, nrows, 2);
- for (col = 0; col < ncols; col++) {
- Segment_put(&dir_seg, &dnullval, row, col);
- }
- }
- G_percent(1, 1, 1);
- }
- /* Scan the start_points layer searching for starting points.
- * Create a heap of starting points ordered by increasing costs.
- */
- init_heap();
- /* read vector with start points */
- if (opt7->answer) {
- struct Map_info In;
- struct line_pnts *Points;
- struct line_cats *Cats;
- struct bound_box box;
- struct start_pt *new_start_pt;
- int cat, type, npoints = 0;
- Points = Vect_new_line_struct();
- Cats = Vect_new_cats_struct();
- Vect_set_open_level(1); /* topology not required */
- if (1 > Vect_open_old(&In, opt7->answer, ""))
- G_fatal_error(_("Unable to open vector map <%s>"), opt7->answer);
- G_message(_("Reading vector map <%s> with start points..."),
- Vect_get_full_name(&In));
-
- Vect_rewind(&In);
- Vect_region_box(&window, &box);
- while (1) {
- /* register line */
- type = Vect_read_next_line(&In, Points, Cats);
- /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
- if (type == -1) {
- G_warning(_("Unable to read vector map"));
- continue;
- }
- else if (type == -2) {
- break;
- }
- if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
- continue;
- npoints++;
- col = (int)Rast_easting_to_col(Points->x[0], &window);
- row = (int)Rast_northing_to_row(Points->y[0], &window);
- new_start_pt =
- (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
- new_start_pt->row = row;
- new_start_pt->col = col;
- Vect_cat_get(Cats, 1, &cat);
- new_start_pt->value = cat;
- new_start_pt->next = NULL;
- if (head_start_pt == NULL) {
- head_start_pt = new_start_pt;
- pres_start_pt = new_start_pt;
- new_start_pt->next = NULL;
- }
- else {
- pres_start_pt->next = new_start_pt;
- pres_start_pt = new_start_pt;
- }
- }
- if (npoints < 1)
- G_fatal_error(_("No start points found in vector map <%s>"), Vect_get_full_name(&In));
- else
- G_verbose_message(_n("%d point found", "%d points found", npoints), npoints);
-
- Vect_close(&In);
- }
- /* read vector with stop points */
- if (opt8->answer) {
- struct Map_info In;
- struct line_pnts *Points;
- struct line_cats *Cats;
- struct bound_box box;
- struct start_pt *new_start_pt;
- int type;
- G_message(_("Reading vector map <%s> with stop points..."), opt8->answer);
- Points = Vect_new_line_struct();
- Cats = Vect_new_cats_struct();
- Vect_set_open_level(1); /* topology not required */
- if (1 > Vect_open_old(&In, opt8->answer, ""))
- G_fatal_error(_("Unable to open vector map <%s>"), opt8->answer);
- Vect_rewind(&In);
- Vect_region_box(&window, &box);
- while (1) {
- /* register line */
- type = Vect_read_next_line(&In, Points, Cats);
- /* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
- if (type == -1) {
- G_warning(_("Unable to read vector map"));
- continue;
- }
- else if (type == -2) {
- break;
- }
- if (!Vect_point_in_box(Points->x[0], Points->y[0], 0, &box))
- continue;
- have_stop_points = TRUE;
- col = (int)Rast_easting_to_col(Points->x[0], &window);
- row = (int)Rast_northing_to_row(Points->y[0], &window);
- new_start_pt =
- (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
- new_start_pt->row = row;
- new_start_pt->col = col;
- new_start_pt->next = NULL;
- if (head_end_pt == NULL) {
- head_end_pt = new_start_pt;
- pres_stop_pt = new_start_pt;
- new_start_pt->next = NULL;
- }
- else {
- pres_stop_pt->next = new_start_pt;
- pres_stop_pt = new_start_pt;
- }
- }
- Vect_close(&In);
- if (!have_stop_points)
- G_fatal_error(_("No stop points found in vector <%s>"), opt8->answer);
- }
- /* read raster with start points */
- if (opt9->answer) {
- int dsize2;
- int fd;
- RASTER_MAP_TYPE data_type2;
- int got_one = 0;
- search_mapset = G_find_raster(opt9->answer, "");
- if (search_mapset == NULL)
- G_fatal_error(_("Raster map <%s> not found"), opt9->answer);
- fd = Rast_open_old(opt9->answer, search_mapset);
- data_type2 = Rast_get_map_type(fd);
- nearest_data_type = data_type2;
- dsize2 = Rast_cell_size(data_type2);
- cell2 = Rast_allocate_buf(data_type2);
- if (!cell2)
- G_fatal_error(_("Unable to allocate memory"));
- G_message(_("Reading raster map <%s> with start points..."), opt9->answer);
- for (row = 0; row < nrows; row++) {
- G_percent(row, nrows, 2);
- Rast_get_row(fd, cell2, row, data_type2);
- ptr2 = cell2;
- for (col = 0; col < ncols; col++) {
- /* Did I understand that concept of cummulative cost map? - (pmx) 12 april 2000 */
- if (!Rast_is_null_value(ptr2, data_type2)) {
- double cellval;
- Segment_get(&cost_seg, &costs, row, col);
- cellval = Rast_get_d_value(ptr2, data_type2);
- if (start_with_raster_vals == 1) {
- insert(cellval, row, col);
- costs.cost_out = cellval;
- costs.nearest = cellval;
- Segment_put(&cost_seg, &costs, row, col);
- }
- else {
- value = &zero;
- insert(zero, row, col);
- costs.cost_out = *value;
- costs.nearest = cellval;
- Segment_put(&cost_seg, &costs, row, col);
- }
- got_one = 1;
- }
- ptr2 = G_incr_void_ptr(ptr2, dsize2);
- }
- }
- G_percent(1, 1, 1);
- Rast_close(fd);
- G_free(cell2);
- if (!got_one)
- G_fatal_error(_("No start points"));
- }
- /* If the starting points are given on the command line start a linked
- * list of cells ordered by increasing costs
- */
- if (head_start_pt) {
- struct start_pt *top_start_pt = NULL;
- top_start_pt = head_start_pt;
- while (top_start_pt != NULL) {
- value = &zero;
- if (top_start_pt->row < 0 || top_start_pt->row >= nrows
- || top_start_pt->col < 0 || top_start_pt->col >= ncols)
- G_fatal_error(_("Specified starting location outside database window"));
- insert(zero, top_start_pt->row, top_start_pt->col);
- Segment_get(&cost_seg, &costs, top_start_pt->row,
- top_start_pt->col);
- costs.cost_out = *value;
- costs.nearest = top_start_pt->value;
- Segment_put(&cost_seg, &costs, top_start_pt->row,
- top_start_pt->col);
- top_start_pt = top_start_pt->next;
- }
- }
- /* Loop through the heap and perform at each cell the following:
- * 1) If an adjacent cell has not already been assigned a value compute
- * the min cost and assign it.
- * 2) Insert the adjacent cell in the heap.
- * 3) Free the memory allocated to the present cell.
- */
- G_debug(1, "total cells: %ld", total_cells);
- G_debug(1, "nrows x ncols: %d", nrows * ncols);
- G_message(_("Finding cost path..."));
- n_processed = 0;
- pres_cell = get_lowest();
- while (pres_cell != NULL) {
- struct cost *ct;
- double N, NE, E, SE, S, SW, W, NW;
- double NNE, ENE, ESE, SSE, SSW, WSW, WNW, NNW;
- N = NE = E = SE = S = SW = W = NW = dnullval;
- NNE = ENE = ESE = SSE = SSW = WSW = WNW = NNW = dnullval;
- /* If we have surpassed the user specified maximum cost, then quit */
- if (maxcost && ((double)maxcost < pres_cell->min_cost))
- break;
- /* If I've already been updated, delete me */
- Segment_get(&cost_seg, &costs, pres_cell->row, pres_cell->col);
- old_min_cost = costs.cost_out;
- if (!Rast_is_d_null_value(&old_min_cost)) {
- if (pres_cell->min_cost > old_min_cost) {
- delete(pres_cell);
- pres_cell = get_lowest();
- continue;
- }
- }
- my_cost = costs.cost_in;
- nearest = costs.nearest;
- row = pres_cell->row;
- col = pres_cell->col;
- G_percent(n_processed++, total_cells, 1);
- /* 9 10 Order in which neighbors
- * 13 5 3 6 14 are visited (Knight move).
- * 1 2
- * 16 8 4 7 15
- * 12 11
- */
- /* drainage directions in degrees CCW from East
- * drainage directions are set for each neighbor and must be
- * read as from neighbor to current cell
- *
- * X = neighbor:
- *
- * 112.5 67.5
- * 157.5 135 90 45 22.5
- * 180 X 360
- * 202.5 225 270 315 337.5
- * 247.5 292.5
- *
- * X = present cell, directions for neighbors:
- *
- * 292.5 247.5
- * 337.5 315 270 225 202.5
- * 360 X 180
- * 22.5 45 90 135 157.5
- * 67.5 112.5
- */
- for (neighbor = 1; neighbor <= total_reviewed; neighbor++) {
- switch (neighbor) {
- case 1:
- col = pres_cell->col - 1;
- cur_dir = 360.0;
- break;
- case 2:
- col = pres_cell->col + 1;
- cur_dir = 180.0;
- break;
- case 3:
- row = pres_cell->row - 1;
- col = pres_cell->col;
- cur_dir = 270.0;
- break;
- case 4:
- row = pres_cell->row + 1;
- cur_dir = 90.0;
- break;
- case 5:
- row = pres_cell->row - 1;
- col = pres_cell->col - 1;
- cur_dir = 315.0;
- break;
- case 6:
- col = pres_cell->col + 1;
- cur_dir = 225.0;
- break;
- case 7:
- row = pres_cell->row + 1;
- cur_dir = 135.0;
- break;
- case 8:
- col = pres_cell->col - 1;
- cur_dir = 45.0;
- break;
- case 9:
- row = pres_cell->row - 2;
- col = pres_cell->col - 1;
- cur_dir = 292.5;
- break;
- case 10:
- col = pres_cell->col + 1;
- cur_dir = 247.5;
- break;
- case 11:
- row = pres_cell->row + 2;
- cur_dir = 112.5;
- break;
- case 12:
- col = pres_cell->col - 1;
- cur_dir = 67.5;
- break;
- case 13:
- row = pres_cell->row - 1;
- col = pres_cell->col - 2;
- cur_dir = 337.5;
- break;
- case 14:
- col = pres_cell->col + 2;
- cur_dir = 202.5;
- break;
- case 15:
- row = pres_cell->row + 1;
- cur_dir = 157.5;
- break;
- case 16:
- col = pres_cell->col - 2;
- cur_dir = 22.5;
- break;
- }
- if (row < 0 || row >= nrows)
- continue;
- if (col < 0 || col >= ncols)
- continue;
- min_cost = dnullval;
- Segment_get(&cost_seg, &costs, row, col);
- switch (neighbor) {
- case 1:
- W = costs.cost_in;
- fcost = (double)(W + my_cost);
- min_cost = pres_cell->min_cost + fcost * EW_fac;
- break;
- case 2:
- E = costs.cost_in;
- fcost = (double)(E + my_cost);
- min_cost = pres_cell->min_cost + fcost * EW_fac;
- break;
- case 3:
- N = costs.cost_in;
- fcost = (double)(N + my_cost);
- min_cost = pres_cell->min_cost + fcost * NS_fac;
- break;
- case 4:
- S = costs.cost_in;
- fcost = (double)(S + my_cost);
- min_cost = pres_cell->min_cost + fcost * NS_fac;
- break;
- case 5:
- NW = costs.cost_in;
- fcost = (double)(NW + my_cost);
- min_cost = pres_cell->min_cost + fcost * DIAG_fac;
- break;
- case 6:
- NE = costs.cost_in;
- fcost = (double)(NE + my_cost);
- min_cost = pres_cell->min_cost + fcost * DIAG_fac;
- break;
- case 7:
- SE = costs.cost_in;
- fcost = (double)(SE + my_cost);
- min_cost = pres_cell->min_cost + fcost * DIAG_fac;
- break;
- case 8:
- SW = costs.cost_in;
- fcost = (double)(SW + my_cost);
- min_cost = pres_cell->min_cost + fcost * DIAG_fac;
- break;
- case 9:
- NNW = costs.cost_in;
- fcost = (double)(N + NW + NNW + my_cost);
- min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
- break;
- case 10:
- NNE = costs.cost_in;
- fcost = (double)(N + NE + NNE + my_cost);
- min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
- break;
- case 11:
- SSE = costs.cost_in;
- fcost = (double)(S + SE + SSE + my_cost);
- min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
- break;
- case 12:
- SSW = costs.cost_in;
- fcost = (double)(S + SW + SSW + my_cost);
- min_cost = pres_cell->min_cost + fcost * V_DIAG_fac;
- break;
- case 13:
- WNW = costs.cost_in;
- fcost = (double)(W + NW + WNW + my_cost);
- min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
- break;
- case 14:
- ENE = costs.cost_in;
- fcost = (double)(E + NE + ENE + my_cost);
- min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
- break;
- case 15:
- ESE = costs.cost_in;
- fcost = (double)(E + SE + ESE + my_cost);
- min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
- break;
- case 16:
- WSW = costs.cost_in;
- fcost = (double)(W + SW + WSW + my_cost);
- min_cost = pres_cell->min_cost + fcost * H_DIAG_fac;
- break;
- }
- /* skip if costs could not be calculated */
- if (Rast_is_d_null_value(&min_cost))
- continue;
- Segment_get(&cost_seg, &costs, row, col);
- old_min_cost = costs.cost_out;
- /* add to list */
- if (Rast_is_d_null_value(&old_min_cost)) {
- costs.cost_out = min_cost;
- costs.nearest = nearest;
- Segment_put(&cost_seg, &costs, row, col);
- insert(min_cost, row, col);
- if (dir == TRUE) {
- Segment_put(&dir_seg, &cur_dir, row, col);
- }
- }
- /* update with lower costs */
- else if (old_min_cost > min_cost) {
- costs.cost_out = min_cost;
- costs.nearest = nearest;
- Segment_put(&cost_seg, &costs, row, col);
- insert(min_cost, row, col);
- if (dir == TRUE) {
- Segment_put(&dir_seg, &cur_dir, row, col);
- }
- }
- }
- if (have_stop_points && time_to_stop(pres_cell->row, pres_cell->col))
- break;
- ct = pres_cell;
- delete(pres_cell);
- pres_cell = get_lowest();
- if (ct == pres_cell)
- G_warning(_("Error, ct == pres_cell"));
- }
- G_percent(1, 1, 1);
- /* free heap */
- free_heap();
-
- /* Open cumulative cost layer for writing */
- cum_fd = Rast_open_new(cum_cost_layer, cum_data_type);
- cell = Rast_allocate_buf(cum_data_type);
- /* Open nearest start point layer */
- if (nearest_layer) {
- nearest_fd = Rast_open_new(nearest_layer, nearest_data_type);
- nearest_cell = Rast_allocate_buf(nearest_data_type);
- }
- else {
- nearest_fd = -1;
- nearest_cell = NULL;
- }
- nearest_size = Rast_cell_size(nearest_data_type);
- /* Copy segmented map to output map */
- G_message(_("Writing output raster map <%s>..."), cum_cost_layer);
- if (nearest_layer) {
- G_message(_("Writing raster map with nearest start point <%s>..."), nearest_layer);
- }
- cell2 = Rast_allocate_buf(data_type);
- {
- void *p;
- void *p2;
- void *p3;
- int cum_dsize = Rast_cell_size(cum_data_type);
- Rast_set_null_value(cell2, ncols, data_type);
- for (row = 0; row < nrows; row++) {
- G_percent(row, nrows, 2);
- if (keep_nulls)
- Rast_get_row(cost_fd, cell2, row, data_type);
- p = cell;
- p2 = cell2;
- p3 = nearest_cell;
- for (col = 0; col < ncols; col++) {
- if (keep_nulls) {
- if (Rast_is_null_value(p2, data_type)) {
- Rast_set_null_value(p, 1, cum_data_type);
- p = G_incr_void_ptr(p, cum_dsize);
- p2 = G_incr_void_ptr(p2, dsize);
- if (nearest_layer) {
- Rast_set_null_value(p3, 1, nearest_data_type);
- p3 = G_incr_void_ptr(p3, nearest_size);
- }
- continue;
- }
- }
- Segment_get(&cost_seg, &costs, row, col);
- min_cost = costs.cost_out;
- nearest = costs.nearest;
- if (Rast_is_d_null_value(&min_cost)) {
- Rast_set_null_value(p, 1, cum_data_type);
- if (nearest_layer)
- Rast_set_null_value(p3, 1, nearest_data_type);
- }
- else {
- if (min_cost > peak)
- peak = min_cost;
- switch (cum_data_type) {
- case CELL_TYPE:
- *(CELL *)p = (CELL)(min_cost + .5);
- break;
- case FCELL_TYPE:
- *(FCELL *)p = (FCELL)(min_cost);
- break;
- case DCELL_TYPE:
- *(DCELL *)p = (DCELL)(min_cost);
- break;
- }
- if (nearest_layer) {
- switch (nearest_data_type) {
- case CELL_TYPE:
- *(CELL *)p3 = (CELL)(nearest);
- break;
- case FCELL_TYPE:
- *(FCELL *)p3 = (FCELL)(nearest);
- break;
- case DCELL_TYPE:
- *(DCELL *)p3 = (DCELL)(nearest);
- break;
- }
- }
- }
- p = G_incr_void_ptr(p, cum_dsize);
- p2 = G_incr_void_ptr(p2, dsize);
- if (nearest_layer)
- p3 = G_incr_void_ptr(p3, nearest_size);
- }
- Rast_put_row(cum_fd, cell, cum_data_type);
- if (nearest_layer)
- Rast_put_row(nearest_fd, nearest_cell, nearest_data_type);
- }
- G_percent(1, 1, 1);
- G_free(cell);
- G_free(cell2);
- if (nearest_layer)
- G_free(nearest_cell);
- }
- if (dir == TRUE) {
- void *p;
- size_t dir_size = Rast_cell_size(dir_data_type);
- dir_fd = Rast_open_new(move_dir_layer, dir_data_type);
- dir_cell = Rast_allocate_buf(dir_data_type);
- G_message(_("Writing output movement direction raster map <%s>..."), move_dir_layer);
- for (row = 0; row < nrows; row++) {
- p = dir_cell;
- for (col = 0; col < ncols; col++) {
- Segment_get(&dir_seg, &cur_dir, row, col);
- *((FCELL *) p) = cur_dir;
- p = G_incr_void_ptr(p, dir_size);
- }
- Rast_put_row(dir_fd, dir_cell, dir_data_type);
- G_percent(row, nrows, 2);
- }
- G_percent(1, 1, 1);
- G_free(dir_cell);
- }
- Segment_close(&cost_seg); /* release memory */
- if (dir == TRUE)
- Segment_close(&dir_seg);
- Rast_close(cost_fd);
- Rast_close(cum_fd);
- if (dir == TRUE)
- Rast_close(dir_fd);
- if (nearest_layer)
- Rast_close(nearest_fd);
- /* writing history file */
- Rast_short_history(cum_cost_layer, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(cum_cost_layer, &history);
- if (dir == TRUE) {
- Rast_short_history(move_dir_layer, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(move_dir_layer, &history);
- }
- if (nearest_layer) {
- Rast_short_history(nearest_layer, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(nearest_layer, &history);
- if (opt9->answer) {
- struct Colors colors;
- Rast_read_colors(opt9->answer, "", &colors);
- Rast_write_colors(nearest_layer, G_mapset(), &colors);
- }
- else {
- struct Colors colors;
- struct Range range;
- CELL min, max;
-
- Rast_read_range(nearest_layer, G_mapset(), &range);
- Rast_get_range_min_max(&range, &min, &max);
- Rast_make_random_colors(&colors, min, max);
- Rast_write_colors(nearest_layer, G_mapset(), &colors);
- }
- }
- /* Create colours for output map */
- /*
- * Rast_read_range (cum_cost_layer, current_mapset, &range);
- * Rast_get_range_min_max(&range, &min, &max);
- * G_make_color_wave(&colors,min, max);
- * Rast_write_colors (cum_cost_layer,current_mapset,&colors);
- */
- G_done_msg(_("Peak cost value: %g"), peak);
- exit(EXIT_SUCCESS);
- }
- int
- process_answers(char **answers, struct start_pt **points,
- struct start_pt **top_start_pt)
- {
- int col, row;
- double east, north;
- struct start_pt *new_start_pt;
- int got_one = 0;
- int point_no = 0;
- *points = NULL;
- if (!answers)
- return (0);
- for (; *answers != NULL; answers += 2) {
- if (!G_scan_easting(*answers, &east, G_projection()))
- G_fatal_error(_("Illegal x coordinate <%s>"), *answers);
- if (!G_scan_northing(*(answers + 1), &north, G_projection()))
- G_fatal_error(_("Illegal y coordinate <%s>"), *(answers + 1));
- if (east < window.west || east > window.east ||
- north < window.south || north > window.north) {
- G_warning(_("Warning, ignoring point outside window: %g, %g"),
- east, north);
- continue;
- }
- else
- got_one = 1;
- row = (window.north - north) / window.ns_res;
- col = (east - window.west) / window.ew_res;
- new_start_pt = (struct start_pt *)(G_malloc(sizeof(struct start_pt)));
- new_start_pt->row = row;
- new_start_pt->col = col;
- new_start_pt->value = ++point_no;
- new_start_pt->next = NULL;
- if (*points == NULL) {
- *points = new_start_pt;
- *top_start_pt = new_start_pt;
- new_start_pt->next = NULL;
- }
- else {
- (*top_start_pt)->next = new_start_pt;
- *top_start_pt = new_start_pt;
- }
- }
- return (got_one);
- }
- int time_to_stop(int row, int col)
- {
- static int total = 0;
- static int hits = 0;
- struct start_pt *points;
- if (total == 0) {
- for (points = head_end_pt;
- points != NULL; points = points->next, total++) ;
- }
- for (points = head_end_pt; points != NULL; points = points->next)
- if (points->row == row && points->col == col) {
- hits++;
- if (hits == total)
- return (1);
- }
- return (0);
- }
|