home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: Science
/
Science.zip
/
gmt_os2.zip
/
src
/
blockmedian.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-28
|
12KB
|
432 lines
/*--------------------------------------------------------------------
* The GMT-system: @(#)blockmedian.c 2.21 4/28/95
*
* Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
* See README file for copying and redistribution conditions.
*--------------------------------------------------------------------*/
/*
blockmedian.c
Takes lon, lat, data, [weight] on stdin or file and writes out one value
per cell, where cellular region is bounded by West East South North and
cell dimensions are delta_x, delta_y.
Author: Walter H. F. Smith
Date: 28 June, 1988
Modified 26 April, 1991-1995 for gmt v2.0 by whfs smith;
added dynamic memory allocation.
Modified: 3 Jan 1995 by PW for gmt 3.0
*/
#include "gmt.h"
int compare_x();
int compare_y();
int compare_index_z();
int median_output();
struct DATA {
int i;
float w;
float x;
float y;
float z;
} *data;
main (argc, argv)
int argc;
char **argv;
{
BOOLEAN error, weighted, offset, report, nofile = TRUE, done = FALSE, first = TRUE;
BOOLEAN b_in = FALSE, b_out = FALSE, single_precision = FALSE, more, skip;
FILE *fp = NULL;
double west, east, south, north, delta_x, delta_y, del_off;
double *in, out[4], idx, idy;
int i, n_x, n_y, ix, iy, index, first_in_cell, first_in_new_cell, fno, n_files = 0, n_args;
int n_lost, n_read, n_pitched, n_cells_filled, n_alloc, x, y, n_expected_fields, n_fields, n_out;
char modifier, buffer[512];
argc = gmt_begin (argc, argv);
west = east = south = north = delta_x = delta_y = 0.0;
del_off = 0.5;
error = weighted = offset = report = FALSE;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
/* Common parameters */
case 'H':
case 'R':
case 'V':
case ':':
case '\0':
error += get_common_args (argv[i], &west, &east, &south, &north);
break;
/* Supplemental parameters */
case 'b':
single_precision = !(argv[i][strlen(argv[i])-1] == 'd');
if (argv[i][2] == 'i')
b_in = TRUE;
else if (argv[i][2] == 'o')
b_out = TRUE;
else
b_in = b_out = TRUE;
break;
case 'I':
gmt_getinc (&argv[i][2], &delta_x, &delta_y);
break;
case 'N':
offset = TRUE;
break;
case 'W':
if ( (modifier = argv[i][2]) == 'i' || modifier == 'I') {
weighted = TRUE;
report = FALSE;
}
else if (modifier == 'O' || modifier == 'o') {
report = TRUE;
weighted = FALSE;
}
else
weighted = report = TRUE;
break;
default:
error = TRUE;
gmt_default_error (argv[i][1]);
break;
}
}
else
n_files++;
}
if (argc == 1 || gmt_quick) {
fprintf (stderr, "blockmedian %s - Block averaging by L1 norm\n\n", GMT_VERSION);
fprintf (stderr, "usage: blockmedian [infile(s)] -I<xinc[m]>[/<yinc>[m]] -R<west/east/south/north>\n");
fprintf (stderr, "\t[-H] [-N] [-V] [-W[i][o] ] [-:] [-b[i|o]i[d]]\n\n");
if (gmt_quick) exit (-1);
fprintf (stderr, "\t-I sets Increment of the grid; enter xinc, optionally xinc/yinc.\n");
fprintf (stderr, "\t Default is yinc = xinc. Append an m [or s] to xinc or yinc to indicate minutes [or seconds],\n");
fprintf (stderr, "\t e.g., -I10m/5m grids longitude every 10 minutes, latitude every 5 minutes.\n");
explain_option ('R');
fprintf (stderr, "\n\tOPTIONS:\n");
explain_option ('H');
fprintf (stderr, "\t-N Offsets registration so block edges are on gridlines.\n");
explain_option ('V');
fprintf (stderr, "\t-W sets Weight options. -WI reads Weighted Input (4 cols: x,y,z,w) but writes only (x,y,z) Output.\n");
fprintf (stderr, "\t -WO reads unWeighted Input (3 cols: x,y,z) but reports sum (x,y,z,w) Output.\n");
fprintf (stderr, "\t -W with no modifier has both weighted Input and Output; Default is no weights used.\n");
explain_option (':');
fprintf (stderr, "\t-b means binary (double) i/o. Append i or o if only input OR output is binary\n");
fprintf (stderr, "\t Append d for double precision [Default is single precision].\n"); explain_option ('.');
exit (-1);
}
if (!project_info.region_supplied) {
fprintf (stderr, "%s: GMT SYNTAX ERROR: Must specify -R option\n", gmt_program);
error++;
}
if (delta_x <= 0.0 || delta_y <= 0.0) {
fprintf (stderr, "%s: GMT SYNTAX ERROR -I option. Must specify positive increment(s)\n", gmt_program);
error = TRUE;
}
if (b_in && gmtdefs.io_header) {
fprintf (stderr, "%s: GMT SYNTAX ERROR. Binary input data cannot have header -H\n", gmt_program);
error++;
}
if (error) exit (-1);
if (b_in) gmt_input = (single_precision) ? bin_float_input : bin_double_input;
if (b_out) gmt_output = (single_precision) ? bin_float_output : bin_double_output;
idx = 1.0 / delta_x;
idy = 1.0 / delta_y;
n_x = rint((east - west) * idx) + 1;
n_y = rint((north - south) * idy) + 1;
if (offset) {
n_x--;
n_y--;
del_off = 0.0;
}
if (gmtdefs.verbose) fprintf (stderr, "W: %.5lf E: %.5lf S: %.5lf N: %.5lf nx: %d ny: %d\n",
west, east, south, north, n_x, n_y);
n_read = 0;
n_pitched = 0;
n_alloc = GMT_CHUNK;
data = (struct DATA *) memory (CNULL, n_alloc, sizeof(struct DATA), "blockmedian");
gmt_data[3] = 1.0; /* Default weight if weights not supplied */
/* Read the input data */
x = (gmtdefs.xy_toggle) ? 1 : 0; y = 1 - x; /* Set up which columns have x and y */
n_expected_fields = (weighted) ? 4 : 3;
if (n_files > 0)
nofile = FALSE;
else
n_files = 1;
n_args = (argc > 1) ? argc : 2;
for (fno = 1; !done && fno < n_args; fno++) { /* Loop over input files, if any */
if (!nofile && argv[fno][0] == '-') continue;
if (nofile) { /* Just read standard input */
fp = stdin;
done = TRUE;
}
else if ((fp = fopen (argv[fno], "r")) == NULL) {
fprintf (stderr, "blockmedian: Cannot open file %s\n", argv[fno]);
continue;
}
if (!nofile && gmtdefs.verbose) fprintf (stderr, "blockmedian: Working on file %s\n", argv[fno]);
if (gmtdefs.io_header) {
for (i = 0; i < gmtdefs.n_header_recs; i++) {
fgets (buffer, 512, fp);
buffer[strlen(buffer)-1] = 0;
if (first && !b_out) (report && !(weighted)) ? printf ("%s weights\n", buffer) : printf ("%s\n", buffer);
}
first = FALSE;
}
more = ((n_fields = gmt_input (fp, n_expected_fields, &in)) == n_expected_fields);
while (more) {
skip = FALSE;
if (bad_float ((float)in[2])) skip = TRUE; /* Skip when z = NaN */
if (!skip) { /* Check if point is inside area */
n_read++;
ix = floor(((in[x] - west) * idx) + del_off);
if ( ix < 0 || ix >= n_x ) skip = TRUE;
iy = floor(((in[y] - south) * idy) + del_off);
if ( iy < 0 || iy >= n_y ) skip = TRUE;
}
if (!skip) {
index = iy * n_x + ix;
data[n_pitched].i = index;
data[n_pitched].w = in[3];
data[n_pitched].x = in[x];
data[n_pitched].y = in[y];
data[n_pitched].z = in[2];
n_pitched++;
if (n_pitched == n_alloc) {
n_alloc += GMT_CHUNK;
data = (struct DATA *) memory ((char *)data, n_alloc, sizeof(struct DATA), "blockmedian");
}
}
more = ((n_fields = gmt_input (fp, n_expected_fields, &in)) == n_expected_fields);
}
if (fp != stdin) fclose(fp);
if (n_fields == -1) n_fields = 0; /* Ok to get EOF */
if (n_fields%n_expected_fields) { /* Got garbage or multiple segment subheader */
fprintf (stderr, "%s: Cannot read X Y Z [W] at line %d, aborts\n", gmt_program, n_read);
exit (-1);
}
}
data = (struct DATA *) memory ((char *)data, n_pitched, sizeof(struct DATA), "blockmedian");
n_lost = n_read - n_pitched;
if (gmtdefs.verbose) fprintf(stderr,"N_read: %d N_used: %d N_outside_area: %d\n",
n_read,n_pitched,n_lost);
/* Ready to go. */
n_out = (report) ? 4 : 3;
/* Sort on index and Z value */
qsort((char *)data, n_pitched, sizeof (struct DATA), compare_index_z);
/* Find n_in_cell and write appropriate output */
first_in_cell = 0;
n_cells_filled = 0;
while (first_in_cell < n_pitched) {
out[3] = data[first_in_cell].w;
first_in_new_cell = first_in_cell + 1;
while ( (first_in_new_cell < n_pitched) && (data[first_in_new_cell].i == data[first_in_cell].i) ) {
out[3] += data[first_in_new_cell].w;
first_in_new_cell++;
}
median_output(first_in_cell, first_in_new_cell, out[3], &out[x], &out[y], &out[2]);
gmt_output (stdout, n_out, out);
n_cells_filled++;
first_in_cell = first_in_new_cell;
}
if (gmtdefs.verbose) fprintf(stderr,"N_cells_filled: %d\n", n_cells_filled);
free((char *)data);
gmt_end (argc, argv);
}
int median_output(first_in_cell, first_in_new_cell, weight_sum, xx, yy, zz)
int first_in_cell, first_in_new_cell;
double *xx, *yy, *zz, weight_sum;
{
double weight_half, weight_count;
int index, n_in_cell;
weight_half = 0.5 * weight_sum;
n_in_cell = first_in_new_cell - first_in_cell;
/* Data are already sorted on z */
index = first_in_cell;
weight_count = data[first_in_cell].w;
while (weight_count < weight_half) {
index++;
weight_count += data[index].w;
}
if ( weight_count == weight_half )
*zz = 0.5 * (data[index].z + data[index + 1].z);
else
*zz = data[index].z;
/* Now do x and y */
if (n_in_cell > 2)
qsort((char *)&data[first_in_cell], n_in_cell, sizeof (struct DATA), compare_x);
index = first_in_cell;
weight_count = data[first_in_cell].w;
while (weight_count < weight_half) {
index++;
weight_count += data[index].w;
}
if ( weight_count == weight_half )
*xx = 0.5 * (data[index].x + data[index + 1].x);
else
*xx = data[index].x;
if (n_in_cell > 2)
qsort((char *)&data[first_in_cell], n_in_cell, sizeof (struct DATA), compare_y);
index = first_in_cell;
weight_count = data[first_in_cell].w;
while (weight_count < weight_half) {
index++;
weight_count += data[index].w;
}
if ( weight_count == weight_half )
*yy = 0.5 * (data[index].y + data[index + 1].y);
else
*yy = data[index].y;
return;
}
int compare_index_z(point_1, point_2)
struct DATA *point_1, *point_2;
{
int index_1, index_2;
float data_1, data_2;
index_1 = point_1->i;
index_2 = point_2->i;
if (index_1 < index_2)
return (-1);
else if (index_1 > index_2)
return (1);
else {
data_1 = point_1->z;
data_2 = point_2->z;
if (data_1 < data_2)
return (-1);
else if (data_1 > data_2)
return (1);
else
return (0);
}
}
int compare_x(point_1, point_2)
struct DATA *point_1, *point_2;
{
int index_1, index_2;
float x_1, x_2;
index_1 = point_1->i;
index_2 = point_2->i;
if (index_1 < index_2)
return (-1);
else if (index_1 > index_2)
return (1);
else {
x_1 = point_1->x;
x_2 = point_2->x;
if (x_1 < x_2)
return (-1);
else if (x_1 > x_2)
return (1);
else
return (0);
}
}
int compare_y(point_1, point_2)
struct DATA *point_1, *point_2;
{
int index_1, index_2;
float y_1, y_2;
index_1 = point_1->i;
index_2 = point_2->i;
if (index_1 < index_2)
return (-1);
else if (index_1 > index_2)
return (1);
else {
y_1 = point_1->y;
y_2 = point_2->y;
if (y_1 < y_2)
return (-1);
else if (y_1 > y_2)
return (1);
else
return (0);
}
}