home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------
- * The GMT-system: @(#)splitxyz.c 2.15 4/11/95
- *
- * Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
- * See README file for copying and redistribution conditions.
- *--------------------------------------------------------------------*/
- /*
- *
- * read a file of lon, lat, zvalue[, distance, azimuth]
- * and split it into profile segments.
- *
- * Author: W. H. F. Smith
- * Date: 24 July, 1991-1995
- */
-
- #include "gmt.h"
-
- #define F_RES 1000 /* Number of points in filter halfwidth */
-
- struct DATA {
- double d;
- double a;
- double x;
- double y;
- double z;
- double w;
- } *data;
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- int i, ndata, n_alloc, nprofiles, begin, end, ix, iy, n_in, n_fields;
-
- BOOLEAN error = FALSE, dh_supplied = FALSE, ok, hilow, map_units = FALSE;
- BOOLEAN binary = FALSE, single_precision = FALSE, more, xy_only = FALSE;
-
- double desired_azim = 90.0, tolerance_azim = 360.0;
- double min_dist = 100.0, xy_filter = 0.0, z_filter = 0.0;
- double d_gap = 10.0, course_change = 0.0, d_to_km;
- double dy, dx, last_d, last_c, last_s, csum, ssum, this_c, this_s, dotprod;
- double mean_azim, fwork[F_RES], *in;
-
- char buffer[512], basename[120], filename[120], format[80];
-
- FILE *fpin = NULL, *fpout = NULL;
-
- void filterz(), filterxy_setup(), filterxy();
-
- argc = gmt_begin (argc, argv);
- basename[0] = '\0'; /* Later, if (basename[0]) we have to write files. */
-
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- switch (argv[i][1]) {
-
- /* Common parameters */
-
- case 'H':
- case 'V':
- case ':':
- case '\0':
- error += get_common_args (argv[i], 0, 0, 0, 0);
- break;
-
- /* Supplemental parameters */
-
- case 'b':
- single_precision = !(argv[i][strlen(argv[i])-1] == 'd');
- binary = TRUE;
- break;
- case 'A':
- if ( (sscanf(&argv[i][2], "%lf/%lf", &desired_azim, &tolerance_azim)) != 2) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -A option: Can't dechiper values\n", gmt_program);
- error = TRUE;
- }
- break;
- case 'C':
- if ( (sscanf(&argv[i][2], "%lf", &course_change)) != 1) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -C option: Can't dechiper value\n", gmt_program);
- error = TRUE;
- }
- break;
- case 'D':
- if ( (sscanf(&argv[i][2], "%lf", &min_dist)) != 1) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -D option: Can't dechiper value\n", gmt_program);
- error = TRUE;
- }
- break;
- case 'F':
- if ( (sscanf(&argv[i][2], "%lf/%lf", &xy_filter, &z_filter)) != 2) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -F option: Can't dechiper values\n", gmt_program);
- error = TRUE;
- }
- break;
- case 'G':
- if ( (sscanf(&argv[i][2], "%lf", &d_gap)) != 1) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -G option: Can't dechiper value\n", gmt_program);
- error = TRUE;
- }
- break;
- case 'M':
- map_units = TRUE;
- break;
- case 'N':
- strcpy(basename, &argv[i][2]);
- break;
- case 'S':
- dh_supplied = TRUE;
- break;
- case 'Z':
- xy_only = TRUE;
- break;
- default:
- error = TRUE;
- gmt_default_error (argv[i][1]);
- break;
- }
- }
- else {
- if ( (fpin = fopen(argv[i], "r")) == NULL) {
- fprintf(stderr,"splitxyz: Cannot open %s\n", argv[i]);
- error = TRUE;
- }
- }
- }
-
- if (argc == 1 || gmt_quick) { /* Display usage */
- fprintf (stderr, "splitxyz %s - Split xyz[dh] files into segments\n\n", GMT_VERSION);
- fprintf(stderr,"usage: splitxyz [<xyz[dh]file>] -C<course_change> [-A<azimuth>/<tolerance>]\n");
- fprintf(stderr,"\t[-D<minimum_distance>] [-F<xy_filter>/<z_filter>] [-G<gap>] [-H] [-M]\n");
- fprintf(stderr,"\t[-N<namestem>] [-S] [-V] [-Z] [-:] [-b[d]]\n\n");
-
- if (gmt_quick) exit (-1);
-
- fprintf(stderr,"\tGive xyz[dh]file name or read stdin.\n");
- fprintf(stderr,"\t-C Profile ends when change of heading exceeds <course_change>.\n");
- fprintf (stderr, "\n\tOPTIONS:\n");
- fprintf(stderr,"\t-A Only write profile if mean direction is w/in +/- <tolerance>\n");
- fprintf(stderr,"\t of <azimuth>. [Default = All].\n");
- fprintf(stderr,"\t-D Only write profile if length is at least <minimum_distance>.\n");
- fprintf(stderr,"\t [Default = 100 dist units].\n");
- fprintf(stderr,"\t-F Filter the data. Give full widths of cosine arch filters for xy and z.\n");
- fprintf(stderr,"\t Defaults are both widths = 0, giving no filtering.\n");
- fprintf(stderr,"\t Use negative width to highpass.\n");
- fprintf(stderr,"\t-G Do not let profiles have gaps exceeding <gap>. [Default = 10 dist units].\n");
- explain_option ('H');
- fprintf(stderr,"\t-M Map units TRUE; x,y in degrees, dist units in km. [Default dist unit = x,y unit].\n");
- fprintf(stderr,"\t-N Write output to separate files named <namestem>.profile#.\n");
- fprintf(stderr,"\t [Default all to stdout, separated by >].\n");
- fprintf(stderr,"\t-S dh is supplied. Input is 5 col x,y,z,d,h with d non-decreasing.\n");
- fprintf(stderr,"\t [Default input is 3 col x,y,z only and computes d,h from the data].\n");
- fprintf(stderr,"\t-Z No z-values. Input is 2 col x,y only\n");
- explain_option ('V');
- explain_option (':');
- fprintf (stderr, "\t-b means binary input (output is always ascii)\n");
- fprintf (stderr, "\t Append d for double precision [Default is single precision].\n"); explain_option ('.');
- explain_option ('.');
- exit(-1);
- }
-
- if (course_change <= 0.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -C option: Course change tolerance must be positive\n", gmt_program);
- error++;
- }
- if (tolerance_azim < 0.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -A option: Azimuth tolerance must be positive\n", gmt_program);
- error++;
- }
- if (d_gap < 0.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -G option: Data gap distance must be positive\n", gmt_program);
- error++;
- }
- if (desired_azim < 0.0 || desired_azim > 360) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -A option: azimuth must be in 0-360 degree range\n", gmt_program);
- error++;
- }
- if (xy_only && dh_supplied) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -Z option: Cannot be used with -S option\n", gmt_program);
- error++;
- }
- if (xy_only && z_filter != 0.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -F option: Cannot specify z-filter while using -Z option\n", gmt_program);
- error++;
- }
-
- if (error) exit (-1);
-
- tolerance_azim *= D2R;
- if (desired_azim > 180.0) desired_azim -= 180.0; /* Put in Easterly strikes */
- desired_azim = D2R * (90.0 - desired_azim); /* Work in cartesian angle and radians */
- course_change *= D2R;
- d_to_km = 0.001 * 2.0 * M_PI * gmtdefs.ellipse[N_ELLIPSOIDS-1].eq_radius / 360.0;
-
- if (fpin == NULL) fpin = stdin;
- n_alloc = GMT_CHUNK;
- ndata = 0;
- i = 0;
- n_in = (dh_supplied) ? 5 : ((xy_only) ? 2 : 3);
- if (xy_only)
- sprintf (format, "%s\t%s\n\0", gmtdefs.d_format, gmtdefs.d_format);
- else
- sprintf (format, "%s\t%s\t%s\n\0", gmtdefs.d_format, gmtdefs.d_format, gmtdefs.d_format);
- data = (struct DATA *) memory (CNULL, n_alloc, sizeof(struct DATA), "splitxyz");
- ix = (gmtdefs.xy_toggle); iy = 1 - ix;
-
- if (binary) gmt_input = (single_precision) ? bin_float_input : bin_double_input;
- if (!binary && gmtdefs.io_header) for (i = 0; i < gmtdefs.n_header_recs; i++) fgets (buffer, 512, fpin);
-
- more = ((n_fields = gmt_input (fpin, n_in, &in)) == n_in);
-
- while (more) {
- i++;
- if (ndata == n_alloc) {
- n_alloc += GMT_CHUNK;
- data = (struct DATA *) memory ((char *)data, n_alloc, sizeof(struct DATA), "splitxyz");
- }
- if (!dh_supplied) {
- data[ndata].x = in[ix];
- data[ndata].y = in[iy];
- if (!xy_only) data[ndata].z = in[2];
- if (ndata) {
- dy = (data[ndata].y - data[ndata-1].y);
- dx = (data[ndata].x - data[ndata-1].x);
- if (map_units) {
- dy *= d_to_km;
- dx *= (d_to_km * cos (0.5 * (data[ndata].y + data[ndata-1].y) * D2R) );
- }
- if (dy == 0.0 && dx == 0.0) {
- data[ndata].d = data[ndata-1].d;
- data[ndata].a = data[ndata-1].a;
- }
- else {
- data[ndata].d = data[ndata-1].d + hypot(dx,dy);
- data[ndata].a = d_atan2(dy,dx);
- }
- }
- else {
- data[ndata].d = data[ndata].a = 0.0;
- }
- ndata++;
- }
- else {
- data[ndata].x = in[ix];
- data[ndata].y = in[iy];
- data[ndata].z = in[2];
- data[ndata].d = in[3];
- data[ndata].a = D2R * (90.0 - in[4]);
- ndata++;
- }
- more = ((n_fields = gmt_input (fpin, n_in, &in)) == n_in);
- }
-
- data = (struct DATA *) memory ((char *)data, ndata, sizeof(struct DATA), "splitxyz");
- if (!dh_supplied) data[0].a = data[1].a;
- if (fpin != stdin) fclose(fpin);
- if (n_fields == -1) n_fields = 0; /* Ok to get EOF */
- if (n_fields%n_in) { /* Got garbage or multiple segment subheader */
- fprintf (stderr, "%s: Cannot read line %d, aborts\n", gmt_program, ndata);
- exit (-1);
- }
-
- /* Now we have read the data and can filter z if necessary. */
-
- if (z_filter < 0.0) {
- hilow = TRUE;
- z_filter = fabs(z_filter);
- filterz(data, ndata, z_filter, fwork, hilow);
- }
- else if (z_filter > 0.0) {
- hilow = FALSE;
- filterz(data, ndata, z_filter, fwork, hilow);
- }
-
- if (xy_filter < 0.0) {
- hilow = TRUE;
- xy_filter = fabs(xy_filter);
- filterxy_setup(fwork);
- }
- else if (xy_filter > 0.0) {
- hilow = FALSE;
- filterxy_setup(fwork);
- }
-
- /* Now we are ready to search for segments. */
-
- nprofiles = 0;
- begin = 0;
- end = begin;
- while (end < ndata-1) {
- last_d = data[begin].d;
- last_c = cos(data[begin].a);
- last_s = sin(data[begin].a);
- csum = last_c;
- ssum = last_s;
- ok = TRUE;
- while (ok && end < ndata-1) {
- end++;
- if (data[end].d - last_d > d_gap) {
- /* Fails due to too much distance gap */
- ok = FALSE;
- continue;
- }
- this_c = cos(data[end].a);
- this_s = sin(data[end].a);
- dotprod = this_c * last_c + this_s * last_s;
- if (fabs(dotprod) > 1.0) dotprod = copysign(1.0, dotprod);
- if (d_acos(dotprod) > course_change) {
- /* Fails due to too much change in azimuth */
- ok = FALSE;
- continue;
- }
- /* Get here when this point belongs with last one: */
- csum += this_c;
- ssum += this_s;
- last_c = this_c;
- last_s = this_s;
- last_d = data[end].d;
- }
-
- /* Get here when we have found a beginning and end */
-
- if (end - begin - 1) {
-
- /* There are at least two points in the list. */
-
- if ((data[end-1].d - data[begin].d) >= min_dist) {
-
- /* List is long enough. Check strike. Compute mean_azim in range [-pi/2, pi/2]: */
-
- mean_azim = d_asin(ssum/sqrt(csum*csum + ssum*ssum));
- mean_azim = fabs(mean_azim - desired_azim);
- if (mean_azim <= tolerance_azim || mean_azim >= (M_PI-tolerance_azim) ) {
-
- /* List has acceptable strike. */
-
- if (xy_filter != 0.0) filterxy(data, begin, end, xy_filter, fwork, hilow);
- nprofiles++;
-
- /* If (basename) we write separate files, else stdout with > marks: */
-
- if (basename[0]) {
- sprintf(filename, "%s.profile%d\0", basename, nprofiles);
- if ( (fpout = fopen(filename, "w")) == NULL) {
- fprintf(stderr,"splitxyz: Cannot create %s\n", argv[i]);
- exit(-1);
- }
- if (xy_only)
- for(i = begin; i < end; i++) fprintf(fpout, format, data[i].x, data[i].y);
- else
- for(i = begin; i < end; i++) fprintf(fpout, format, data[i].x, data[i].y, data[i].z);
- fclose(fpout);
- if (gmtdefs.verbose) fprintf(stderr,"Wrote %d points to file %s\n", end-begin, filename);
- }
- else {
- printf("> Start profile # %d\n", nprofiles);
- if (xy_only)
- for (i = begin; i < end; i++) printf(format, data[i].x, data[i].y);
- else
- for (i = begin; i < end; i++) printf(format, data[i].x, data[i].y, data[i].z);
- }
- }
- }
- }
- begin = end;
- }
-
- /* Get here when all profiles have been found and written. */
-
- if (gmtdefs.verbose) fprintf(stderr,"splitxyz: Split %d data into %d files.\n", ndata, nprofiles);
- free((char *)data);
-
- gmt_end (argc, argv);
- }
-
-
- void filterz(data, ndata, z_filter, fwork, hilow)
- struct DATA *data;
- int ndata, hilow;
- double z_filter, *fwork;
- {
-
- double half_width, sum, dt, tmp;
- int i, j, k, istart, istop;
-
- half_width = 0.5 * z_filter;
- sum = 0.0;
- dt = F_RES/half_width;
- tmp = M_PI / F_RES;
- for (i = 0; i < F_RES; i++) {
- fwork[i] = 1.0 + cos(i*tmp);
- sum += fwork[i];
- }
- for (i = 1; i < F_RES; i++) {
- fwork[i] /= sum;
- }
-
- j = 0;
- istart = 0;
- istop = 0;
- while(j < ndata) {
- while(istart < ndata && data[istart].d - data[j].d <= -half_width) istart++;
- while(istop < ndata && data[istop].d - data[j].d < half_width) istop++;
- sum = 0.0;
- data[j].w = 0.0;
- for(i = istart; i < istop; i++) {
- k = floor(dt*fabs(data[i].d - data[j].d));
- sum += fwork[k];
- data[j].w += (data[i].z * fwork[k]);
- }
- data[j].w /= sum;
- j++;
- }
- if (hilow) {
- for (i = 0; i < ndata; i++) data[i].z = data[i].z - data[i].w;
- }
- else {
- for (i = 0; i < ndata; i++) data[i].z = data[i].w;
- }
- return;
- }
-
- void filterxy_setup(fwork)
- double *fwork;
- {
- int i;
- double tmp, sum = 0.0;
-
- tmp = M_PI / F_RES;
- for (i = 0; i < F_RES; i++) {
- fwork[i] = 1.0 + cos(i*tmp);
- sum += fwork[i];
- }
- for (i = 1; i < F_RES; i++) {
- fwork[i] /= sum;
- }
- return;
- }
-
- void filterxy(data, begin, end, xy_filter, fwork, hilow)
- struct DATA *data;
- int begin, end, hilow;
- double xy_filter, *fwork;
- {
- int i, j, k, istart, istop;
- double half_width, dt, sum;
-
- half_width = 0.5 * fabs(xy_filter);
- dt = F_RES/half_width;
-
- j = begin;
- istart = begin;
- istop = begin;
- while(j < end) {
- while(istart < end && data[istart].d - data[j].d <= -half_width) istart++;
- while(istop < end && data[istop].d - data[j].d < half_width) istop++;
- sum = 0.0;
- data[j].w = 0.0;
- for(i = istart; i < istop; i++) {
- k = floor(dt*fabs(data[i].d - data[j].d));
- sum += fwork[k];
- data[j].w += (data[i].x * fwork[k]);
- }
- data[j].w /= sum;
- j++;
- }
- if (hilow) {
- for (i = begin; i < end; i++) data[i].x = data[i].x - data[i].w;
- }
- else {
- for (i = begin; i < end; i++) data[i].x = data[i].w;
- }
-
- j = begin;
- istart = begin;
- istop = begin;
- while(j < end) {
- while(istart < end && data[istart].d - data[j].d <= -half_width) istart++;
- while(istop < end && data[istop].d - data[j].d < half_width) istop++;
- sum = 0.0;
- data[j].w = 0.0;
- for(i = istart; i < istop; i++) {
- k = floor(dt*fabs(data[i].d - data[j].d));
- sum += fwork[k];
- data[j].w += (data[i].y * fwork[k]);
- }
- data[j].w /= sum;
- j++;
- }
- if (hilow) {
- for (i = begin; i < end; i++) data[i].y = data[i].y - data[i].w;
- }
- else {
- for (i = begin; i < end; i++) data[i].y = data[i].w;
- }
-
- return;
- }
-
-
-