@@ -55,13 +55,16 @@ struct PROJECT_CTRL { /* All control options for this program (except common arg
5555 bool active ;
5656 char col [PROJECT_N_FARGS ]; /* Character codes for desired output in the right order */
5757 } F ;
58- struct PROJECT_G { /* -G<inc>[/<colat>][+h ] */
58+ struct PROJECT_G { /* -G<inc>[<unit>[ /<colat>][+c|h][+n ] */
5959 bool active ;
6060 bool header ;
61+ bool number ;
6162 bool through_C ;
6263 unsigned int mode ;
6364 double inc ;
6465 double colat ;
66+ char unit ;
67+ int d_mode ; /* Could be negative */
6568 } G ;
6669 struct PROJECT_L { /* -L[w][<l_min>/<l_max>] */
6770 bool active ;
@@ -323,8 +326,8 @@ static void Free_Ctrl (struct GMT_CTRL *GMT, struct PROJECT_CTRL *C) { /* Deallo
323326static int usage (struct GMTAPI_CTRL * API , int level ) {
324327 const char * name = gmt_show_name_and_purpose (API , THIS_MODULE_LIB , THIS_MODULE_CLASSIC_NAME , THIS_MODULE_PURPOSE );
325328 if (level == GMT_MODULE_PURPOSE ) return (GMT_NOERROR );
326- GMT_Usage (API , 0 , "usage: %s [<table>] -C<ox>/<oy> [-A<azimuth>] [-E<bx>/<by>] [-F<flags>] [-G<dist>[/<colat>][+c|h ]] "
327- "[-L[w|<l_min>/<l_max>]] [-N] [-Q] [-S] [-T<px>/<py>] [%s] [-W<w_min>/<w_max>] [-Z<major>[unit][/<minor>/<azimuth>][+e|n ]] "
329+ GMT_Usage (API , 0 , "usage: %s [<table>] -C<ox>/<oy> [-A<azimuth>] [-E<bx>/<by>] [-F<flags>] [-G<dist>[unit][ /<colat>][+c][+h][+n ]] "
330+ "[-L[w|<l_min>/<l_max>]] [-N] [-Q] [-S] [-T<px>/<py>] [%s] [-W<w_min>/<w_max>] [-Z<major>[unit][/<minor>/<azimuth>][+e]] "
328331 "[%s] [%s] [%s] [%s] [%s] [%s] [%s] [%s] [%s] [%s] [%s] [%s]\n" ,
329332 name , GMT_V_OPT , GMT_b_OPT , GMT_d_OPT , GMT_e_OPT , GMT_f_OPT , GMT_g_OPT , GMT_h_OPT , GMT_i_OPT , GMT_o_OPT ,
330333 GMT_q_OPT , GMT_s_OPT , GMT_colon_OPT , GMT_PAR_OPT );
@@ -361,12 +364,15 @@ static int usage (struct GMTAPI_CTRL *API, int level) {
361364 "Note 2: z refers to all input data columns beyond the required x,y. "
362365 "Note 3: If -G is set, -F is not available and output defaults to rsp "
363366 "[Default is all fields, i.e., -Fxyzpqrs]." );
364- GMT_Usage (API , 1 , "\n-G<dist>[/<colat>][+c|h]" );
367+ GMT_Usage (API , 1 , "\n-G<dist>[<unit>][ /<colat>][+c|h]" );
365368 GMT_Usage (API , -2 , "Generate (r,s,p) points along profile every <dist> units. (No input data used.) "
366369 "If E given, will generate from C to E; else must give -L<l_min>/<l_max> for length. "
367370 "Optionally, append /<colat> for a small circle path through C and E (requires -C -E). Some modifiers:" );
368371 GMT_Usage (API , 3 , "+c If given -T and -C, compute and use <colat> of C [90]." );
369372 GMT_Usage (API , 3 , "+h Place information about the pole in a segment header [no header]." );
373+ GMT_Usage (API , 3 , "+n Increment specifies the number of points instead (requires -C -E or -Z)." );
374+ GMT_Usage (API , -2 , "For geographic profile, append e (meter), f (foot), k (km), M (mile), n (nautical mile), u (survey foot), d (arc degree), "
375+ "m (arc minute), or s (arc second) to <inc> [k]. " );
370376 GMT_Usage (API , 1 , "\n-L[w|<l_min>/<l_max>]" );
371377 GMT_Usage (API , -2 , "Check the Length along the projected track and use only certain points:n" );
372378 GMT_Usage (API , 3 , "%s Append w to only use those points Within the span from C to E (Must have set -E)." , GMT_LINE_BULLET );
@@ -387,7 +393,6 @@ static int usage (struct GMTAPI_CTRL *API, int level) {
387393 GMT_Usage (API , 1 , "\n-Z<major>[unit][/<minor>/<azimuth>][+e|n]" );
388394 GMT_Usage (API , -2 , "With -G and -C, generate an ellipse of given major and minor axes and the azimuth of the major axis." );
389395 GMT_Usage (API , 3 , "+e Adjust increment to fix perimeter exactly [use increment as given in -G]." );
390- GMT_Usage (API , 3 , "+n Indicate that increment in -G specifies the number of unique perimeter points instead." );
391396 GMT_Usage (API , -2 , "For a degenerate ellipse, i.e., circle, you may just give <major> only as the <diameter>. "
392397 "Append e (meter), f (foot), k (km), M (mile), n (nautical mile), u (survey foot), d (arc degree), "
393398 "m (arc minute), or s (arc second) to <major> [k]; we assume -G is in the same units (unless +n is used). "
@@ -411,7 +416,14 @@ static int parse (struct GMT_CTRL *GMT, struct PROJECT_CTRL *Ctrl, struct GMT_OP
411416 struct GMT_OPTION * opt = NULL ;
412417 struct GMTAPI_CTRL * API = GMT -> parent ;
413418
414- for (opt = options ; opt ; opt = opt -> next ) if (opt -> option == 'N' ) Ctrl -> N .active = true; /* Must find -N first, if given */
419+ for (opt = options ; opt ; opt = opt -> next ) {
420+ if (opt -> option == 'N' ) /* Must find -N first, if given */
421+ Ctrl -> N .active = true;
422+ else if (opt -> option == 'Q' ) { /* Geographic coordinates */
423+ gmt_set_geographic (GMT , GMT_IN );
424+ gmt_set_geographic (GMT , GMT_OUT );
425+ }
426+ }
415427
416428 for (opt = options ; opt ; opt = opt -> next ) {
417429 switch (opt -> option ) {
@@ -488,24 +500,33 @@ static int parse (struct GMT_CTRL *GMT, struct PROJECT_CTRL *Ctrl, struct GMT_OP
488500 opt -> arg [len ] = 0 ; /* Temporarily remove the trailing + sign */
489501 ch = & opt -> arg [len ];
490502 }
491- if ((c = gmt_first_modifier (GMT , opt -> arg , "ch " ))) { /* Process any modifiers */
503+ if ((c = gmt_first_modifier (GMT , opt -> arg , "chn " ))) { /* Process any modifiers */
492504 pos = 0 ; /* Reset to start of new word */
493- while (gmt_getmodopt (GMT , 'G' , c , "ch " , & pos , p , & n_errors ) && n_errors == 0 ) {
505+ while (gmt_getmodopt (GMT , 'G' , c , "chn " , & pos , p , & n_errors ) && n_errors == 0 ) {
494506 switch (p [0 ]) {
495- case 'c' : Ctrl -> G .through_C = true; break ; /* Compute required colatitude for small ircle to go through C */
507+ case 'c' : Ctrl -> G .through_C = true; break ; /* Compute required colatitude for small circle to go through C */
496508 case 'h' : Ctrl -> G .header = true; break ; /* Output segment header */
509+ case 'n' : Ctrl -> G .number = true; break ; /* Gave number of points rather than increment */
497510 default : break ; /* These are caught in gmt_getmodopt so break is just for Coverity */
498511 }
499512 }
500513 c [0 ] = '\0' ; /* Hide modifiers */
501514 }
502515 if (sscanf (opt -> arg , "%[^/]/%s" , txt_a , txt_b ) == 2 ) { /* Got dist/colat */
503516 Ctrl -> G .mode = 1 ;
504- Ctrl -> G .inc = atof (txt_a );
505517 n_errors += gmt_verify_expectations (GMT , gmt_M_type (GMT , GMT_IN , GMT_Y ), gmt_scanf_arg (GMT , txt_b , gmt_M_type (GMT , GMT_IN , GMT_Y ), false, & Ctrl -> G .colat ), txt_b );
506518 }
507519 else
508- Ctrl -> G .inc = atof (opt -> arg );
520+ strcpy (txt_a , opt -> arg );
521+ if (Ctrl -> G .number ) {
522+ Ctrl -> Z .number = true; /* Since -Z +n needs backwards compatibility support */
523+ Ctrl -> G .inc = atof (txt_a );
524+ }
525+ else {
526+ if (gmt_M_is_geographic (GMT , GMT_IN ) && strchr (GMT_LEN_UNITS , txt_a [strlen (txt_a )- 1 ]) == NULL ) /* No unit given, append k for default km */
527+ strcat (txt_a , "k" );
528+ Ctrl -> G .d_mode = gmt_get_distance (GMT , txt_a , & (Ctrl -> G .inc ), & (Ctrl -> G .unit ));
529+ }
509530 if (ch ) ch [0 ] = '+' ; /* Restore the obsolete plus-sign */
510531 if (c ) c [0 ] = '+' ; /* Restore modifier */
511532 break ;
@@ -568,6 +589,8 @@ static int parse (struct GMT_CTRL *GMT, struct PROJECT_CTRL *Ctrl, struct GMT_OP
568589 Ctrl -> Z .minor = atof (txt_b );
569590 }
570591 else { /* Watch out for units and convert to km */
592+ if (gmt_M_is_geographic (GMT , GMT_IN ) && strchr (GMT_LEN_UNITS , txt_a [strlen (txt_a )- 1 ]) == NULL ) /* No unit given, append k for default km */
593+ strcat (txt_a , "k" );
571594 Ctrl -> Z .mode = gmt_get_distance (GMT , txt_a , & (Ctrl -> Z .major ), & (Ctrl -> Z .unit ));
572595 (void ) gmt_get_distance (GMT , txt_b , & (Ctrl -> Z .minor ), & dummy );
573596 }
@@ -588,6 +611,9 @@ static int parse (struct GMT_CTRL *GMT, struct PROJECT_CTRL *Ctrl, struct GMT_OP
588611 if (Ctrl -> N .active )
589612 Ctrl -> Z .minor = Ctrl -> Z .major = atof (opt -> arg );
590613 else {
614+ strcpy (txt_a , opt -> arg );
615+ if (gmt_M_is_geographic (GMT , GMT_IN ) && strchr (GMT_LEN_UNITS , txt_a [strlen (txt_a )- 1 ]) == NULL ) /* No unit given, append k for default km */
616+ strcat (txt_a , "k" );
591617 Ctrl -> Z .mode = gmt_get_distance (GMT , opt -> arg , & (Ctrl -> Z .minor ), & (Ctrl -> Z .unit ));
592618 Ctrl -> Z .major = Ctrl -> Z .minor ;
593619 }
@@ -611,6 +637,8 @@ static int parse (struct GMT_CTRL *GMT, struct PROJECT_CTRL *Ctrl, struct GMT_OP
611637 n_errors ++ ;
612638 }
613639
640+ n_errors += gmt_M_check_condition (GMT , Ctrl -> G .number && !(Ctrl -> C .active && Ctrl -> E .active ),
641+ "Option -G: Can only use +n if both -C and -E are specified\n" );
614642 n_errors += gmt_M_check_condition (GMT , Ctrl -> L .active && !Ctrl -> L .constrain && Ctrl -> L .min >= Ctrl -> L .max ,
615643 "Option -L: w_min must be < w_max\n" );
616644 n_errors += gmt_M_check_condition (GMT , Ctrl -> W .active && Ctrl -> W .min >= Ctrl -> W .max ,
@@ -635,6 +663,8 @@ static int parse (struct GMT_CTRL *GMT, struct PROJECT_CTRL *Ctrl, struct GMT_OP
635663 "Option -N: Cannot be used with -G<dist>/<colat>\n" );
636664 n_errors += gmt_M_check_condition (GMT , Ctrl -> G .through_C && !Ctrl -> C .active ,
637665 "Option -G: Modifier +c requires both -C and -T\n" );
666+ n_errors += gmt_M_check_condition (GMT , Ctrl -> Z .active && !Ctrl -> G .active ,
667+ "Option -Z: Requires option -G as well\n" );
638668 n_errors += gmt_M_check_condition (GMT , Ctrl -> G .through_C && !Ctrl -> T .active ,
639669 "Option -G: Modifier +c requires both -C and -T\n" );
640670 n_errors += gmt_check_binary_io (GMT , 2 );
@@ -761,12 +791,10 @@ EXTERN_MSC int GMT_project (void *V_API, int mode, void *args) {
761791 if (GMT -> current .map .dist [GMT_MAP_DIST ].arc ) { /* Got angular measures, convert to km */
762792 Ctrl -> Z .minor *= (GMT -> current .proj .KM_PR_DEG / GMT -> current .map .dist [GMT_MAP_DIST ].scale ); /* Now in km */
763793 Ctrl -> Z .major *= (GMT -> current .proj .KM_PR_DEG / GMT -> current .map .dist [GMT_MAP_DIST ].scale ); /* Now in km */
764- if (!Ctrl -> Z .number ) Ctrl -> G .inc *= (GMT -> current .proj .KM_PR_DEG / GMT -> current .map .dist [GMT_MAP_DIST ].scale ); /* Now in km */
765794 }
766795 else {
767796 Ctrl -> Z .minor /= (GMT -> current .map .dist [GMT_MAP_DIST ].scale * METERS_IN_A_KM ); /* Now in km */
768797 Ctrl -> Z .major /= (GMT -> current .map .dist [GMT_MAP_DIST ].scale * METERS_IN_A_KM ); /* Now in km */
769- if (!Ctrl -> Z .number ) Ctrl -> G .inc /= (GMT -> current .map .dist [GMT_MAP_DIST ].scale * METERS_IN_A_KM ); /* Now in km */
770798 }
771799 }
772800 }
@@ -813,10 +841,24 @@ EXTERN_MSC int GMT_project (void *V_API, int mode, void *args) {
813841 P .find_new_point = true;
814842 }
815843 if (Ctrl -> G .active ) { /* Hardwire 3 output columns and set their types */
844+ if (gmt_M_is_geographic (GMT , GMT_IN ) && Ctrl -> G .d_mode ) {
845+ if (gmt_init_distaz (GMT , Ctrl -> G .unit , Ctrl -> G .d_mode , GMT_MAP_DIST ) == GMT_NOT_A_VALID_TYPE )
846+ Return (GMT_NOT_A_VALID_TYPE );
847+ }
816848 P .n_outputs = 3 ;
817849 gmt_set_column_type (GMT , GMT_OUT , GMT_X , (Ctrl -> N .active ) ? GMT_IS_FLOAT : GMT_IS_LON );
818850 gmt_set_column_type (GMT , GMT_OUT , GMT_Y , (Ctrl -> N .active ) ? GMT_IS_FLOAT : GMT_IS_LAT );
819851 gmt_set_column_type (GMT , GMT_OUT , GMT_Z , GMT_IS_FLOAT );
852+ if (Ctrl -> G .number ) { /* Must compute great circle separation and divide to get increment */
853+ double L ;
854+ if (gmt_M_is_geographic (GMT , GMT_IN ))
855+ L = 0.001 * gmt_great_circle_dist_meter (GMT , Ctrl -> C .x , Ctrl -> C .y , Ctrl -> E .x , Ctrl -> E .y );
856+ else
857+ L = hypot (Ctrl -> C .x - Ctrl -> E .x , Ctrl -> C .y - Ctrl -> E .y );
858+ Ctrl -> G .inc = L / (Ctrl -> G .inc - 1.0 );
859+ }
860+ else if (Ctrl -> Q .active && Ctrl -> G .unit != 'k' )
861+ Ctrl -> G .inc *= 0.001 / GMT -> current .map .dist [GMT_MAP_DIST ].scale ; /* Now in km */
820862 }
821863 else if (!Ctrl -> N .active ) { /* Decode and set the various output column types in the geographic case */
822864 for (col = 0 ; col < P .n_outputs ; col ++ ) {
@@ -937,6 +979,7 @@ EXTERN_MSC int GMT_project (void *V_API, int mode, void *args) {
937979 double h = pow (Ctrl -> Z .major - Ctrl -> Z .minor , 2.0 ) / pow (Ctrl -> Z .major + Ctrl -> Z .minor , 2.0 );
938980 Ctrl -> L .min = 0.0 ;
939981 Ctrl -> L .max = M_PI * (Ctrl -> Z .major + Ctrl -> Z .minor ) * (1.0 + (3.0 * h )/(10.0 + sqrt (4.0 - 3.0 * h ))); /* Ramanujan approximation of ellipse circumference */
982+ if (gmt_M_is_geographic (GMT , GMT_IN )) Ctrl -> L .max /= GMT -> current .proj .DIST_KM_PR_DEG ;
940983 if (Ctrl -> Z .number ) /* Want a specific number of points */
941984 Ctrl -> G .inc = Ctrl -> L .max / rint (Ctrl -> G .inc );
942985 else if (Ctrl -> Z .exact ) { /* Adjust inc to fit the ellipse perimeter exactly */
0 commit comments