home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------
- * The GMT-system: @(#)project.c 2.10 24 Jul 1995
- *
- * Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
- * See README file for copying and redistribution conditions.
- *--------------------------------------------------------------------*/
- /*
- * project.c
- * reads (x,y,[z]) data and writes some combination of (x,y,z,p,q,u,v),
- * where p,q is the distance along,across the track of the projection of (x,y),
- * and u,v are the un-transformed (x,y) coordinates of the projected position.
- * Can also create (x,y) along track.
-
- Author: Walter H. F. Smith
- Date: 19 April, 1988.
- Modified: 4 December 1988, to be more flexible.
- Complete rebuild 22 June, 1989 to use vector products and do more things.
- version 2.0
-
- */
-
- #include "gmt.h"
-
- int compare_distances();
- int do_flat_earth();
- int solve_right_spherical_triangle();
- int sphere_azim_dist();
- void oblique_setup();
- void oblique_transform();
- void make_euler_matrix();
- void matrix_3v();
- void matrix_2v();
- void sphere_project_setup();
- void flat_project_setup();
-
- struct DATA {
- double a[7];
- } *p_data;
-
- int output_choice[7];
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- int i, j, k, n_definitions, n_outputs, n_used, n_read, ix, iy, n_alloc = GMT_CHUNK;
- int nc, ne, np, nl, nw;
-
- double xx, yy, zz, x_a, y_a, x_b, y_b, x_p, y_p, d_to_km, cos_theta, sin_theta;
- double theta, d_inc = 0.0, d_along, xy[2];
-
- double azimuth = 0.0, l_min = 0.0, l_max = 0.0, w_min = 0.0, w_max = 0.0;
- double a[3], b[3], x[3], xt[3], pole[3], center[3], e[9];
-
- BOOLEAN check_length, check_width, convert_units, dateline, error, find_new_point, flat_earth;
- BOOLEAN generate, greenwich, origin_set, pole_set, rads, sort_output, stay_within, two_points;
-
- FILE *fp = NULL;
-
- char modifier, record_str[100], heading[7][100], format1[20], format2[20], txt_a[32], txt_b[32];
-
- argc = gmt_begin (argc, argv);
-
- check_length = check_width = dateline = error = find_new_point = flat_earth = generate = greenwich = FALSE;
- pole_set = sort_output = stay_within = two_points = convert_units = FALSE;
- rads = TRUE;
- x_a = x_b = x_p = y_a = y_b = y_p = 0.0;
- n_definitions = 0;
- n_outputs = 0;
- j = 1;
- for (i = 0; i < 7; i++) output_choice[i] = 0;
- sprintf (format1, "%s\t\0", gmtdefs.d_format);
- sprintf (format2, "%s\n\0", gmtdefs.d_format);
-
- 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 'F':
- for (j = 2, k = 0; argv[i][j]; j++, k++) {
- switch (argv[i][j]) {
- case 'x':
- output_choice[k] = 0;
- break;
- case 'y':
- output_choice[k] = 1;
- break;
- case 'z':
- output_choice[k] = 2;
- break;
- case 'p':
- output_choice[k] = 3;
- break;
- case 'q':
- output_choice[k] = 4;
- break;
- case 'r':
- output_choice[k] = 5;
- find_new_point = TRUE;
- break;
- case 's':
- output_choice[k] = 6;
- find_new_point = TRUE;
- break;
- default:
- fprintf (stderr, "%s: GMT SYNTAX ERROR -F option: Unrecognized choice %c\n", gmt_program, argv[i][j]);
- error = TRUE;
- }
- n_outputs++;
- }
- break;
- case 'A':
- azimuth = atof(&argv[i][2]);
- n_definitions++;
- break;
- case 'C':
- nc = sscanf(&argv[i][2], "%[^/]/%s", txt_a, txt_b);
- x_a = ddmmss_to_degree (txt_a);
- y_a = ddmmss_to_degree (txt_b);
- origin_set = TRUE;
- break;
- case 'D':
- modifier = argv[i][2];
- if (modifier == 'D' || modifier == 'd') {
- dateline = TRUE;
- }
- else if (modifier == 'g' || modifier == 'G') {
- greenwich = TRUE;
- }
- else if (modifier) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -D option: Unrecognized modifier %c\n", gmt_program, modifier);
- error = TRUE;
- }
- break;
- case 'E':
- ne = sscanf(&argv[i][2], "%[^/]/%s", txt_a, txt_b);
- x_b = ddmmss_to_degree (txt_a);
- y_b = ddmmss_to_degree (txt_b);
- two_points = TRUE;
- n_definitions++;
- break;
- case 'G':
- generate = TRUE;
- d_inc = atof(&argv[i][2]);
- break;
- case 'L':
- check_length = TRUE;
- modifier = argv[i][2];
- if (modifier == 'W' || modifier == 'w') {
- stay_within = TRUE;
- }
- else {
- nl = sscanf(&argv[i][2], "%lf/%lf", &l_min, &l_max);
- }
- break;
- case 'M':
- convert_units = TRUE;
- break;
- case 'N':
- flat_earth = TRUE;
- break;
- case 'S':
- sort_output = TRUE;
- break;
- case 'T':
- np = sscanf(&argv[i][2], "%[^/]/%s", txt_a, txt_b);
- x_p = ddmmss_to_degree (txt_a);
- y_p = ddmmss_to_degree (txt_b);
- pole_set = TRUE;
- n_definitions++;
- break;
- case 'W':
- nw = sscanf(&argv[i][2], "%lf/%lf", &w_min, &w_max);
- check_width = TRUE;
- break;
- default:
- error = TRUE;
- gmt_default_error (argv[i][1]);
- break;
- }
- }
- else {
- if ((fp = fopen(argv[i],"r")) == NULL) {
- fprintf (stderr, "Cannot open file %s\n", argv[i]);
- exit(-1);
- }
- }
- }
-
- if (argc == 1 || gmt_quick) {
- fprintf (stderr, "project %s - project data onto line or great circle, generate track, or translate coordiantes\n\n", GMT_VERSION);
- fprintf(stderr,"usage: project [file] -C<ox>/<oy> -F<flags> [-A<azimuth>] [-D<d_or_g>]\n");
- fprintf(stderr,"\t[-E<bx>/<by>] [-G<dist>] [-H] [-L[w][<l_min>/<l_max>]] [-M] [-N] [-S]\n");
- fprintf(stderr,"\t[-T<px>/<py>] [-V] [-W<w_min>/<w_max>] [-:]\n\n");
-
- if (gmt_quick) exit (-1);
-
- fprintf(stderr,"\tproject will read stdin or file, and does not want input if -G option.\n");
- fprintf(stderr,"\tThe projection may be defined in (only) one of three ways:\n");
- fprintf(stderr,"\t (1) by a center -C and an azimuth -A,\n");
- fprintf(stderr,"\t (2) by a center -C and end point of the path -E,\n");
- fprintf(stderr,"\t (3) by a center -C and a roTation pole position -T.\n");
- fprintf(stderr,"\t In a spherical projection [default], all cases place the central meridian\n");
- fprintf(stderr,"\t of the transformed coordinates (p,q) through -C (p = 0 at -C). The equator\n");
- fprintf(stderr,"\t of the (p,q) system (line q = 0) passes through -C and makes an angle\n");
- fprintf(stderr,"\t <azimuth> with North (case 1), or passes through -E (case 2), or is\n");
- fprintf(stderr,"\t determined by the pole -T (case 3). In (3), point -C need not be on equator.\n");
- fprintf(stderr,"\t In a cartesian [-F option] projection, p = q = 0 at -O in all cases;\n");
- fprintf(stderr,"\t (1) and (2) orient the p axis, while (3) orients the q axis.\n\n");
- fprintf(stderr,"\t-flags: Indicate what output you want as one or more of xyzpqrs in any order;\n");
- fprintf(stderr,"\t where x,y,[z] refer to input data locations and optional values,\n");
- fprintf(stderr,"\t p,q are the coordinates of x,y in the projection's coordinate system,\n");
- fprintf(stderr,"\t r,s is the projected position of x,y (taking q = 0) in the (x,y) coordinate system.\n");
- fprintf(stderr,"\t p,q may be scaled from degrees into kilometers by the -M option. See -L, -M, -W\n\n");
- fprintf(stderr,"\t-C<ox>/<oy> sets the location of the center.\n");
- fprintf (stderr, "\n\tOPTIONS:\n");
- fprintf(stderr,"\t-A<azimuth> sets the option (1) Azimuth, (degrees CW from North).\n");
- fprintf(stderr,"\t-D will force the location of the Discontinuity in the r coordinate;\n");
- fprintf(stderr,"\t -Dd (dateline) means [-180 < r < 180], -Dg (greenwich) means [0 < r < 360].\n");
- fprintf(stderr,"\t The default does not check; in spherical case this usually results in [-180,180].\n");
- fprintf(stderr,"\t-E<bx>/<by> sets the option (2) location of end point E.\n");
- fprintf(stderr,"\t-G means Generate (r,s,p) points along profile every <dist> units. (No input data used.)\n");
- fprintf(stderr,"\t If E given, will generate from A to E; else must give -L<l_min>/<l_max> for length.\n");
- explain_option ('H');
- fprintf(stderr,"\t-L Check the Length along the projected track and use only certain points.\n");
- fprintf(stderr,"\t -Lw will use only those points Within the span from A to E (Must have set -E).\n");
- fprintf(stderr,"\t -L<l_min>/<l_max> will only use points whose p is [l_min <= p <= l_max].\n");
- fprintf(stderr,"\t Default uses all points. Note p = 0 at A and increases toward E in azim direction.\n");
- fprintf(stderr,"\t-M means convert to Map units, so x,y,r,s are degrees,\n");
- fprintf(stderr,"\t while p,q,dist,l_min,l_max,w_min,w_max are km.\n");
- fprintf(stderr,"\t If not set, then p,q,dist,l_min,l_max,w_min,w_max are assumed to be in same units as x,y,r,s.\n");
- fprintf(stderr,"\t-N means Flat_earth; a cartesian projection is made. Default is spherical.\n");
- fprintf(stderr,"\t-S means the output should be Sorted into increasing p value.\n");
- fprintf(stderr,"\t-T<px>/<py> sets the option (3) location of the roTation pole to the projection.\n");
- explain_option ('V');
- fprintf(stderr,"\t-W Check the width across the projected track and use only certain points.\n");
- fprintf(stderr,"\t This will use only those points whose q is [w_min <= q <= w_max].\n");
- fprintf(stderr,"\t Note that q is positive to your LEFT as you walk from A toward B in azim direction.\n");
- explain_option (':');
- fprintf(stderr,"\tWarning: project is CASE SENSITIVE. Enter flags in lower case, other options in UPPER CASE.\n");
- exit(-1);
- }
-
- if ( !(origin_set && nc == 2) ) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -C option. Correct syntax: -C<lon0>/<lat0>\n", gmt_program);
- error++;
- }
- if (two_points && ne != 2) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -E option. Correct syntax: -E<lon1>/<lat1>\n", gmt_program);
- error++;
- }
- if (pole_set && np != 2) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -T option. Correct syntax: -T<lonp>/<latp>\n", gmt_program);
- error++;
- }
- if (check_length && !stay_within && nl != 2) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -L option. Correct syntax: -L[w | <min>/<max>]\n", gmt_program);
- error++;
- }
- if (check_width && (nw != 2 || w_min >= w_max)) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -L option. Correct syntax: -L[w | <min>/<max>]\n", gmt_program);
- error++;
- }
- if (azimuth < 0.0 || azimuth >= 360.0) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -A option. Must specify azimuth in 0-360 degree range\n", gmt_program);
- error++;
- }
- if ( n_definitions != 1) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR: Specify only one of -A, -E, and -T\n", gmt_program);
- error++;
- }
- if ( two_points && (x_a == x_b) && (y_a == y_b) ) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -E option: Second point must differ from origin!\n", gmt_program);
- error++;
- }
- if ( generate && l_min == l_max && !(two_points)) { /* We don't know how long to generate */
- fprintf (stderr, "%s: GMT SYNTAX ERROR -G option: Must also specify -Lmin/max or use -E instead\n", gmt_program);
- error++;
- }
- if ( generate && d_inc <= 0.0) { /* No increment given */
- fprintf (stderr, "%s: GMT SYNTAX ERROR -G option: Must specify a positive increment\n", gmt_program);
- error++;
- }
- if (stay_within && !(two_points) ) { /* Same problem. */
- fprintf (stderr, "%s: GMT SYNTAX ERROR -L option: Must specify -Lmin/max or use -E instead\n", gmt_program);
- error++;
- }
- if (n_outputs > 7) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR -F option: Too many output columns selected (%d)\n", gmt_program, n_outputs);
- error++;
- }
- if (n_outputs <= 0 && !(generate) ) {
- fprintf (stderr, "%s: GMT SYNTAX ERROR: Must specify desired output with -F\n", gmt_program);
- error++;
- }
-
- if (error) exit (-1);
-
-
- p_data = (struct DATA *) memory (CNULL, n_alloc, sizeof (struct DATA), "project");
-
- d_to_km = 0.001 * 2.0 * M_PI * gmtdefs.ellipse[N_ELLIPSOIDS-1].eq_radius / 360.0;
-
- if (generate && two_points && (l_min == l_max) ) stay_within = TRUE; /* Default generate from A to B */
-
- /* Set up rotation matrix e for flat earth, or pole and center for spherical; get l_min, l_max if stay_within */
-
- if (flat_earth) {
- flat_project_setup(y_a, x_a, y_b, x_b, y_p, x_p, &azimuth, e, two_points, pole_set);
- /* Azimuth is now changed to cartesian theta in radians */
- if (stay_within) {
- l_min = 0.0;
- xx = x_b - x_a;
- yy = y_b - y_a;
- l_max = d_sqrt(xx*xx + yy*yy);
- if (convert_units) l_max *= d_to_km;
- }
- }
- else {
- if (pole_set) {
- oblique_setup(y_p, x_p, pole, y_a, x_a, center, pole_set, rads);
- }
- else {
- sphere_project_setup(y_a, x_a, a, y_b, x_b, b, &azimuth, pole, center, two_points, rads);
- }
- /* Azimuth is now changed to radians */
- if (stay_within) {
- l_min = 0.0;
- l_max = dot3v(a,b);
- l_max = d_acos(l_max) * R2D;
- if (convert_units) l_max *= d_to_km;
- }
- }
-
- /* Now things are initialized. We will work in degrees for awhile, so we convert things: */
-
- if (convert_units) {
- d_inc /= d_to_km;
- l_min /= d_to_km;
- l_max /= d_to_km;
- w_min /= d_to_km;
- w_max /= d_to_km;
- }
-
- /* Now we are ready to work */
-
- n_used = 0;
- n_read = 0;
-
- if (generate) {
- n_outputs = 3;
- output_choice[0] = 5;
- output_choice[1] = 6;
- output_choice[2] = 3;
- d_along = l_min;
- while (d_along < l_max) {
- p_data[n_used].a[3] = d_along;
- n_used++;
- d_along = l_min + n_used * d_inc;
- if (n_used == (n_alloc-1)) {
- n_alloc += GMT_CHUNK;
- p_data = (struct DATA *) memory ((char *)p_data, n_alloc, sizeof (struct DATA), "project");
- }
- }
- p_data[n_used].a[3] = l_max;
- n_used ++;
- find_new_point = TRUE;
- }
-
- else {
- if (fp == NULL) fp = stdin;
-
- if (gmtdefs.io_header) {
- fgets(record_str, 100, fp);
- sscanf(record_str, "%s %s %s", heading[0], heading[1], heading[2]);
- if (! (heading[2]) ) strcpy(heading[2],"z");
- strcpy(heading[3],"p");
- strcpy(heading[4],"q");
- strcpy(heading[5],"r");
- strcpy(heading[6],"s");
- for (i = 1; i < gmtdefs.n_header_recs; i++) fgets(record_str, 100, fp);
- }
-
- zz = 0.0;
- ix = (gmtdefs.xy_toggle) ? 1 : 0; iy = 1 - ix; /* Set up which columns have x and y */
- while ( (fgets(record_str, 100, fp) != NULL) ) {
- sscanf (record_str, "%lf %lf %lf", &xy[ix], &xy[iy], &zz);
- xx = xy[0]; yy = xy[1];
-
- n_read ++;
-
- if (flat_earth) {
- x[0] = xx - x_a;
- x[1] = yy - y_a;
- matrix_2v (e,x,xt);
- }
- else {
- oblique_transform(yy, xx, &xt[1], &xt[0], pole, center, rads);
- }
- if(check_length) {
- if (xt[0] < l_min) continue;
- if (xt[0] > l_max) continue;
- }
- if (check_width) {
- if (xt[1] < w_min) continue;
- if (xt[1] > w_max) continue;
- }
- p_data[n_used].a[0] = xx;
- p_data[n_used].a[1] = yy;
- p_data[n_used].a[2] = zz;
- p_data[n_used].a[3] = xt[0];
- p_data[n_used].a[4] = xt[1];
- n_used++;
- if (n_used == n_alloc) {
- n_alloc += GMT_CHUNK;
- p_data = (struct DATA *) memory ((char *)p_data, n_alloc, sizeof (struct DATA), "project");
- }
- }
-
-
- if (fp != stdin) fclose(fp);
-
- if (sort_output) qsort((char *)p_data, n_used, sizeof (struct DATA), compare_distances);
- }
-
- /* Get here when all data are loaded with p,q and p is in increasing order if desired. */
-
- if (find_new_point) { /* We need to find r,s */
-
- if (flat_earth) {
- cos_theta = cos(azimuth);
- sin_theta = sin(azimuth);
- for (i = 0; i < n_used; i++) {
- p_data[i].a[5] = x_a + p_data[i].a[3] * cos_theta;
- p_data[i].a[6] = y_a + p_data[i].a[3] * sin_theta;
- while (greenwich && p_data[i].a[5] < 0.0) p_data[i].a[5] += 360.0;
- while (dateline && p_data[i].a[5] > 180.0) p_data[i].a[5] -= 360.0;
- }
- }
- else {
- xx = x_a;
- yy = y_a;
- geo_to_cart(&yy, &xx, x, rads);
- for (i = 0; i < n_used; i++) {
- theta = p_data[i].a[3];
- make_euler_matrix(pole, e, &theta, rads);
- matrix_3v(e,x,xt);
- cart_to_geo(&yy, &xx, xt, rads);
- p_data[i].a[5] = xx;
- p_data[i].a[6] = yy;
- while (greenwich && p_data[i].a[5] < 0.0) p_data[i].a[5] += 360.0;
- while (dateline && p_data[i].a[5] > 180.0) p_data[i].a[5] -= 360.0;
- }
- }
- }
-
- /* At this stage, all values are still in degrees. */
-
- if (convert_units) {
- for (i = 0; i < n_used; i++) {
- p_data[i].a[3] *= d_to_km;
- p_data[i].a[4] *= d_to_km;
- }
- }
-
- /* Now output */
-
- if (gmtdefs.io_header) {
- if (generate) {
- printf("lon\tlat\tdist\n");
- }
- else {
- for (j = 0; j < n_outputs-1; j++) {
- printf("%s\t", heading[output_choice[j]]);
- }
- printf("%s\n",heading[output_choice[j]]);
- }
- }
-
- for (i = 0; i < n_used; i++) {
- for (j = 0; j < n_outputs-1; j++) printf(format1, p_data[i].a[output_choice[j]]);
- printf(format2, p_data[i].a[output_choice[j]]);
- }
-
- if (gmtdefs.verbose) fprintf(stderr, "N read, N used: %d %d\n", n_read, n_used);
-
- free ((char *)p_data);
-
- gmt_end (argc, argv);
- }
-
- int compare_distances(point_1, point_2)
-
- struct DATA *point_1, *point_2;
- {
- double d_1, d_2;
-
- d_1 = point_1->a[3];
- d_2 = point_2->a[3];
-
- if (d_1 < d_2)
- return (-1);
- if (d_1 > d_2)
- return (1);
- else
- return (0);
- }
-
- void oblique_setup(plat, plon, p, clat, clon, c, c_given, rads)
- double plat, plon, *p, clat, clon, *c;
- int c_given, rads;
- {
- /* routine sets up a unit 3-vector p, the pole of an
- oblique projection, given plat, plon, the position
- of this pole in the usual coordinate frame.
- c_given = TRUE means that clat, clon are to be used
- as the usual coordinates of a point through which the
- user wants the central meridian of the oblique
- projection to go. If such a point is not given, then
- the central meridian will go through p and the usual
- N pole. In either case, a unit 3-vector c is created
- which is the directed normal to the plane of the central
- meridian, pointing in the positive normal (east) sense.
- rads = TRUE if we need to convert plat, plon, clat, clon
- from degrees to radians. */
-
- double s[3]; /* s points to the south pole */
-
- s[0] = s[1] = 0.0;
- s[2] = -1.0;
-
- geo_to_cart(&plat, &plon, p, rads);
-
- if (c_given) { /* s points to user's clat, clon */
- geo_to_cart(&clat, &clon, s, rads);
- }
- cross3v(p, s, c);
- normalize3v(c);
- }
-
- void oblique_transform(xlat, xlon, x_t_lat, x_t_lon, p, c, rads)
- double xlat, xlon, *x_t_lat, *x_t_lon, *p, *c;
- int rads;
- {
- /* routine takes the point x at conventional (xlat, xlon) and
- computes the transformed coordinates (x_t_lat, x_t_lon) in
- an oblique reference frame specified by the unit 3-vectors
- p (the pole) and c (the directed normal to the oblique
- central meridian). p and c have been computed earlier by
- the routine oblique_setup(). rads = TRUE if lats and lons
- are in degrees. */
-
- double x[3], p_cross_x[3], temp1, temp2;
-
- geo_to_cart(&xlat, &xlon, x, rads);
-
- temp1 = dot3v(x,p);
- *x_t_lat = d_asin(temp1);
-
- cross3v(p,x,p_cross_x);
- normalize3v(p_cross_x);
-
- temp1 = dot3v(p_cross_x, c);
- temp2 = dot3v(x, c);
- *x_t_lon = copysign( d_acos(temp1), temp2);
-
- if (rads) {
- *x_t_lat *= R2D;
- *x_t_lon *= R2D;
- }
- }
-
- void make_euler_matrix(p, e, theta, rads)
- double *p, *e, *theta;
- int rads;
- {
- /* Routine to fill an euler matrix e with the elements
- needed to rotate a 3-vector about the pole p through
- an angle theta. p is a unit 3-vector. If rads = TRUE,
- we have to convert theta from degrees into radians before
- we use it. */
-
- double cos_theta, sin_theta, one_minus_cos_theta;
- double pxsin, pysin, pzsin, temp;
-
- if (rads) {
- *theta *= D2R;
- }
- cos_theta = cos(*theta);
- sin_theta = sin(*theta);
- one_minus_cos_theta = 1.0 - cos_theta;
-
- pxsin = p[0] * sin_theta;
- pysin = p[1] * sin_theta;
- pzsin = p[2] * sin_theta;
-
- temp = p[0] * one_minus_cos_theta;
- e[0] = temp * p[0] + cos_theta;
- e[1] = temp * p[1] - pzsin;
- e[2] = temp * p[2] + pysin;
-
- temp = p[1] * one_minus_cos_theta;
- e[3] = temp * p[0] + pzsin;
- e[4] = temp * p[1] + cos_theta;
- e[5] = temp * p[2] - pxsin;
-
- temp = p[2] * one_minus_cos_theta;
- e[6] = temp * p[0] - pysin;
- e[7] = temp * p[1] + pxsin;
- e[8] = temp * p[2] + cos_theta;
- }
-
- void matrix_3v(a,x,b)
- double *a, *x, *b;
- {
- /* routine to find b, where Ax = b, A is a 3 by 3 square matrix,
- and x and b are 3-vectors. A is stored row wise, that is:
-
- A = { a11, a12, a13, a21, a22, a23, a31, a32, a33 } */
-
- b[0] = x[0]*a[0] + x[1]*a[1] + x[2]*a[2];
- b[1] = x[0]*a[3] + x[1]*a[4] + x[2]*a[5];
- b[2] = x[0]*a[6] + x[1]*a[7] + x[2]*a[8];
- }
-
- void matrix_2v(a,x,b)
- double *a, *x, *b;
- {
- /* routine to find b, where Ax = b, A is a 2 by 2 square matrix,
- and x and b are 2-vectors. A is stored row wise, that is:
-
- A = { a11, a12, a21, a22 } */
-
- b[0] = x[0]*a[0] + x[1]*a[1];
- b[1] = x[0]*a[2] + x[1]*a[3];
- }
-
- void sphere_project_setup(alat, alon, a, blat, blon, b, azim, p, c, two_pts, rads)
- double alat, alon, *a, blat, blon, *b, *azim, *p, *c;
- int two_pts, rads;
- {
- /* routine to initialize a pole vector, p, and a central meridian
- normal vector, c, for use in projecting points onto a great circle.
-
- The great circle is specified in either one of two ways:
- if (two_pts), then the user has given two points, a and b,
- which specify the great circle (directed from a to b);
- if !(two_pts), then the user has given one point, a, and an azimuth,
- azim, clockwise from north, which defines the projection.
-
- The strategy is to use the oblique_transform operations above,
- in such a way that the great circle of the projection is the
- equator of an oblique transform, and the central meridian goes
- through a. Then the transformed longitude gives the distance
- along the projection circle, and the transformed latitude gives
- the distance normal to the projection circle.
-
- If (two_pts), then p = normalized(a X b). If not, we temporarily
- create p_temp = normalized(a X n), where n is the north pole.
- p_temp is then rotated about a through the angle azim to give p.
- After p is found, then c = normalized(p X a).
- */
-
- double e[9]; /* Euler roatation matrix, if needed */
- double neg_azim;
-
- /* First find p vector */
-
- if (two_pts) {
- geo_to_cart(&alat, &alon, a, rads);
- geo_to_cart(&blat, &blon, b, rads);
- cross3v(a, b, p);
- normalize3v(p);
- }
- else {
- geo_to_cart(&alat, &alon, a, rads);
- b[0] = b[1] = 0.0; /* set b to north pole */
- b[2] = 1.0;
- cross3v(a, b, c); /* use c for p_temp */
- normalize3v(c);
- /* make_euler_matrix(a, e, azim, rads); */
- neg_azim = -(*azim);
- make_euler_matrix(a, e, &neg_azim, rads);
- if (rads) *azim *= D2R;
- matrix_3v(e, c, p); /* c (p_temp) rotates to p */
- }
-
- /* Now set c vector */
-
- cross3v(p, a, c);
- normalize3v(c);
- }
-
- void flat_project_setup(alat, alon, blat, blon, plat, plon, azim, e, two_pts, pole_set)
- double alat, alon, blat, blon, plat, plon, *azim, *e;
- int two_pts;
- BOOLEAN pole_set;
-
- {
- /* Sets up stuff for rotation of cartesian 2-vectors, analogous
- to the spherical three vector stuff above. Also change azim
- to the cartesian theta, counterclockwise from the x axis. */
-
- if (two_pts) {
- *azim = d_atan2((blat - alat), (blon - alon));
- }
- else if (pole_set) {
- *azim = d_atan2((plat - alat), (plon - alon)) - 0.5 * M_PI;
- }
- else {
- *azim = D2R * (90.0 - *azim);
- }
-
- e[0] = e[3] = cos(*azim);
- e[1] = sin(*azim);
- e[3] = -e[1];
- }
-
-
-
-