Skip to content

Commit

Permalink
Leading zeros (#7655)
Browse files Browse the repository at this point in the history
* WIP allow leading zeros in degree annotations

See #5153.

* Get DDD working for latitudes

* Added explanation for DDD to table (#7656)

* Further implementation of #7475

* Another manual update related to #7475

* gmt.conf.rst: FORMAT_GEO_OUT, DDD means 3 digits for longitude, 2 digits for latitude

---------

Co-authored-by: Paul Wessel <pwessel@hawaii.edu>
Co-authored-by: KristofKoch <45796239+KristofKoch@users.noreply.github.com>
Co-authored-by: andreas <panden@gmail.com>
  • Loading branch information
4 people authored Jul 20, 2023
1 parent 5bb0b11 commit 4d392a4
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 77 deletions.
9 changes: 5 additions & 4 deletions doc/rst/source/gmt.conf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,11 @@ FORMAT Parameters
**D** Use :term:`FORMAT_FLOAT_OUT` for floating point degrees [default]
**+D** Output longitude in the range [0,360]
**-D** Output longitude in the range [-360,0]
**ddd** Fixed format integer degrees
**:** Delimiter used
**mm** Fixed format integer arc minutes
**ss** Fixed format integer arc seconds
**DDD** Fixed format integer degrees (3 digits for longitude, 2 digits for latitude)
**ddd** Integer degrees
**:** Delimiter used (this will translate to degree, minute, seconds symbols on maps)
**mm** Fixed format integer arc minutes (2 digits)
**ss** Fixed format integer arc seconds (2 digits)
**.xxx** Floating fraction of previous integer field, fixed width
**F** Encode sign using WESN suffix
**G** Same as **F** but with a leading space before suffix
Expand Down
110 changes: 53 additions & 57 deletions src/gmt_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,7 @@ void gmtlib_reset_input (struct GMT_CTRL *GMT) {
GMT_LOCAL void gmtio_format_geo_output (struct GMT_CTRL *GMT, bool is_lat, double geo, char *text) {
int k, n_items, d, m, s, m_sec, h_pos = 0;
bool minus;
char hemi[3] = {""}, *f = NULL;
char hemi[3] = {""}, *use_format = NULL;
static char *suffix[2][2] = {{"W", "E"}, {"S", "N"}}; /* Just for decimal degrees when no_sign is true */

if (is_lat) { /* Column is supposedly latitudes */
Expand All @@ -1233,14 +1233,14 @@ GMT_LOCAL void gmtio_format_geo_output (struct GMT_CTRL *GMT, bool is_lat, doubl
}
else gmt_lon_range_adjust (GMT->current.io.geo.range, &geo); /* Adjust longitudes */
if (GMT->current.io.geo.decimal) { /* Easy */
f = (GMT->current.io.o_format[is_lat]) ? GMT->current.io.o_format[is_lat] : GMT->current.setting.format_float_out;
use_format = (GMT->current.io.o_format[is_lat]) ? GMT->current.io.o_format[is_lat] : GMT->current.setting.format_float_out;
if (GMT->current.io.geo.no_sign) {
k = (geo < 0.0) ? 0 : 1;
sprintf (text, f, fabs(geo));
sprintf (text, use_format, fabs(geo));
strcat (text, suffix[is_lat][k]);
}
else
sprintf (text, f, geo);
sprintf (text, use_format, geo);
return;
}

Expand All @@ -1258,20 +1258,21 @@ GMT_LOCAL void gmtio_format_geo_output (struct GMT_CTRL *GMT, bool is_lat, doubl
if (GMT->current.io.geo.order[k] >= 0) n_items++; /* How many of d, m, and s are requested as integers */
minus = gmtlib_geo_to_dms (geo, n_items, GMT->current.io.geo.f_sec_to_int, &d, &m, &s, &m_sec); /* Break up into d, m, s, and remainder */
if (minus) text[0] = '-'; /* Must manually insert leading minus sign when degree == 0 */
use_format = (is_lat ? gmt_strrep(GMT->current.io.geo.format, "%3.3d", "%2.2d") : strdup(GMT->current.io.geo.format));
if (GMT->current.io.geo.n_sec_decimals) { /* Wanted fraction printed */
if (n_items == 3)
sprintf (&text[minus], GMT->current.io.geo.y_format, d, m, s, m_sec, hemi);
sprintf (&text[minus], use_format, d, m, s, m_sec, hemi);
else if (n_items == 2)
sprintf (&text[minus], GMT->current.io.geo.y_format, d, m, m_sec, hemi);
sprintf (&text[minus], use_format, d, m, m_sec, hemi);
else
sprintf (&text[minus], GMT->current.io.geo.y_format, d, m_sec, hemi);
sprintf (&text[minus], use_format, d, m_sec, hemi);
}
else if (n_items == 3)
sprintf (&text[minus], GMT->current.io.geo.y_format, d, m, s, hemi);
sprintf (&text[minus], use_format, d, m, s, hemi);
else if (n_items == 2)
sprintf (&text[minus], GMT->current.io.geo.y_format, d, m, hemi);
sprintf (&text[minus], use_format, d, m, hemi);
else
sprintf (&text[minus], GMT->current.io.geo.y_format, d, hemi);
sprintf (&text[minus], use_format, d, hemi);
}

/* Various functions to support {grd2xyz,xyz2grd}_func.c */
Expand Down Expand Up @@ -2184,10 +2185,19 @@ GMT_LOCAL int gmtio_get_dms_order (struct GMT_CTRL *GMT, char *text, struct GMT_
if (i != 0) error++; /* Only valid as first flag */
break;
case 'D': /* Want to use decimal degrees using FORMAT_FLOAT_OUT [Default] */
S->decimal = true;
if (i > 1) error++; /* Only valid as first or second flag */
if (S->order[0] < 0) /* First time we encounter a D */
S->order[0] = order++;
else if (text[i-1] != 'D') /* Done it before, previous char must be D */
error++;
n_DD++;
break;
case 'd': /* Degree */
if (S->order[0] < 0) /* First time we encounter a d */
S->order[0] = order++;
else if (text[i-1] != 'd') /* Done it before, previous char must be d */
error++;
n_d++;
break;
case 'F': /* Want to use WESN to encode sign */
S->wesn = (i == 0) ? -1 : 1;
if (S->no_sign) error++; /* Cannot mix A and F */
Expand All @@ -2202,13 +2212,6 @@ GMT_LOCAL int gmtio_get_dms_order (struct GMT_CTRL *GMT, char *text, struct GMT_
S->no_sign = true;
if (i != i1 || S->wesn) error++; /* Only valid as last flag */
break;
case 'd': /* Degree */
if (S->order[0] < 0) /* First time we encounter a d */
S->order[0] = order++;
else if (text[i-1] != 'd') /* Done it before, previous char must be y */
error++;
n_d++;
break;
case 'm': /* Minute */
if (S->order[1] < 0) /* First time we encounter a m */
S->order[1] = order++;
Expand Down Expand Up @@ -2249,6 +2252,13 @@ GMT_LOCAL int gmtio_get_dms_order (struct GMT_CTRL *GMT, char *text, struct GMT_
}
}

if (n_DD > 1) { /* Leading zeros flag */
S->leading_zeros = true;
n_d = 3;
}
else if (n_DD == 1) /* One D means decimal */
S->decimal = true;

if (S->decimal) return (GMT_NOERROR); /* Easy formatting choice */

/* Then get the actual order by inverting table */
Expand All @@ -2271,7 +2281,6 @@ GMT_LOCAL int gmtio_get_dms_order (struct GMT_CTRL *GMT, char *text, struct GMT_
error += (n_x && n_dec != 1); /* .xxx is the proper form */
error += (n_x == 0 && n_dec); /* Period by itself and not delimiter? */
error += (n_dec > 1); /* Only one period with xxx */
error += (n_DD > 1); /* Only one occurrence of D */
error += ((n_F > 1) || (n_G > 1)); /* Only one occurrence of F or G */
error += ((n_G + n_F) > 1); /* Only one of either F or G */
S->n_sec_decimals = n_x;
Expand Down Expand Up @@ -7027,40 +7036,28 @@ int gmtlib_geo_C_format (struct GMT_CTRL *GMT) {
/* here we depend on FORMAT_FLOAT_OUT begin set. This will not be true when FORMAT_GEO_MAP is parsed but will be
* handled at the end of gmt_begin. For gmtset and --PAR later we will be OK as well. */
if (!GMT->current.setting.format_float_out[0]) return (GMT_NOERROR); /* Quietly return and deal with this later in gmt_begin */
sprintf (S->x_format, "%s", GMT->current.setting.format_float_out);
sprintf (S->y_format, "%s", GMT->current.setting.format_float_out);
sprintf (S->format, "%s", GMT->current.setting.format_float_out);
}
else { /* Some form of dd:mm:ss */
char fmt[GMT_LEN64] = {""};
/* First add %s for the W,E,S,N string (or NULL) for pre-value hemisphere */
sprintf (fmt, "%%s");
strcat (S->x_format, fmt);
strcat (S->y_format, fmt);
sprintf (S->x_format, "%%03d");
sprintf (S->y_format, "%%02d");
if (S->order[1] >= 0) { /* Need minutes too */
strcat (S->x_format, S->delimiter[0]);
strcat (S->y_format, S->delimiter[0]);
sprintf (fmt, "%%02d");
strcat (S->x_format, fmt);
strcat (S->y_format, fmt);
if (S->leading_zeros)
sprintf (S->format, "%%3.3d");
else
sprintf (S->format, "%%d");
if (S->order[1] >= 0) { /* Need minutes too */
strcat (S->format, S->delimiter[0]);
strcat (S->format, "%02d");
}
if (S->order[2] >= 0) { /* .. and seconds */
strcat (S->x_format, S->delimiter[1]);
strcat (S->y_format, S->delimiter[1]);
sprintf (fmt, "%%02d");
strcat (S->x_format, fmt);
strcat (S->y_format, fmt);
strcat (S->format, S->delimiter[1]);
strcat (S->format, "%02d");
}
if (S->n_sec_decimals) { /* even add format for fractions of second (or minutes or degrees) */
snprintf (fmt, GMT_LEN64, ".%%%d.%dd", S->n_sec_decimals, S->n_sec_decimals);
strcat (S->x_format, fmt);
strcat (S->y_format, fmt);
strcat (S->format, fmt);
}
/* Finally add %s for the W,E,S,N string (or NULL) for post-value hemisphere */
sprintf (fmt, "%%s");
strcat (S->x_format, fmt);
strcat (S->y_format, fmt);
strcat (S->format, "%s");
}
return (GMT_NOERROR);
}
Expand All @@ -7069,6 +7066,7 @@ int gmtlib_geo_C_format (struct GMT_CTRL *GMT) {
int gmtlib_plot_C_format (struct GMT_CTRL *GMT) {
unsigned int i, j, length;
struct GMT_GEO_IO *S = &GMT->current.plot.calclock.geo;
char *d_fmt[2] = {"%d", "%3.3d"};

/* Determine the plot geographic location formats. */

Expand All @@ -7084,29 +7082,27 @@ int gmtlib_plot_C_format (struct GMT_CTRL *GMT) {
* handled at the end of gmt_begin. For gmtset and --PAR later we will be OK as well. */
if (!GMT->current.setting.format_float_out[0]) return GMT_NOERROR; /* Quietly return and deal with this later in gmt_begin */

len = sprintf (S->x_format, "%s", GMT->current.setting.format_float_out);
sprintf (S->y_format, "%s", GMT->current.setting.format_float_out);
len = sprintf (S->format, "%s", GMT->current.setting.format_float_out);
if (GMT->current.setting.map_degree_symbol != gmt_none)
{ /* But we want the degree symbol appended */
S->x_format[len] = (char)GMT->current.setting.ps_encoding.code[GMT->current.setting.map_degree_symbol];
S->y_format[len] = (char)GMT->current.setting.ps_encoding.code[GMT->current.setting.map_degree_symbol];
S->x_format[len+1] = S->y_format[len+1] = '\0';
S->format[len] = (char)GMT->current.setting.ps_encoding.code[GMT->current.setting.map_degree_symbol];
S->format[len+1] = '\0';
}
strcat (S->x_format, "%s");
strcat (S->y_format, "%s");
strcat (S->format, "%s");
}
else { /* Must cover all the 6 forms of dd[:mm[:ss]][.xxx] */
char fmt[GMT_LEN256] = {""};
unsigned int id = S->leading_zeros ? 1 : 0;

/* Level 0: degrees only. index 0 is integer degrees, index 1 is [possibly] fractional degrees */

strcat (GMT->current.plot.format[0][0], "%d"); /* ddd */
strcat (GMT->current.plot.format[0][0], d_fmt[id]); /* ddd */
if (S->order[1] == GMT_NOTSET && S->n_sec_decimals > 0) { /* ddd.xxx format */
snprintf (fmt, GMT_LEN256, "%%d.%%%d.%dd", S->n_sec_decimals, S->n_sec_decimals);
strcat (GMT->current.plot.format[0][1], fmt);
}
else /* ddd format */
strcat (GMT->current.plot.format[0][1], "%d"); /* ddd */
strcat (GMT->current.plot.format[0][1], d_fmt[id]); /* ddd */
if (GMT->current.setting.map_degree_symbol != gmt_none)
{ /* But we want the degree symbol appended */
snprintf (fmt, GMT_LEN256, "%c", (int)GMT->current.setting.ps_encoding.code[GMT->current.setting.map_degree_symbol]);
Expand All @@ -7116,8 +7112,8 @@ int gmtlib_plot_C_format (struct GMT_CTRL *GMT) {

/* Level 1: degrees and minutes only. index 0 is integer minutes, index 1 is [possibly] fractional minutes */

strcat (GMT->current.plot.format[1][0], "%d"); /* ddd */
strcat (GMT->current.plot.format[1][1], "%d");
strcat (GMT->current.plot.format[1][0], d_fmt[id]); /* ddd */
strcat (GMT->current.plot.format[1][1], d_fmt[id]);
if (GMT->current.setting.map_degree_symbol != gmt_none)
{ /* We want the degree symbol appended */
sprintf (fmt, "%c", (int)GMT->current.setting.ps_encoding.code[GMT->current.setting.map_degree_symbol]);
Expand All @@ -7142,8 +7138,8 @@ int gmtlib_plot_C_format (struct GMT_CTRL *GMT) {

/* Level 2: degrees, minutes, and seconds. index 0 is integer seconds, index 1 is [possibly] fractional seconds */

strcat (GMT->current.plot.format[2][0], "%d");
strcat (GMT->current.plot.format[2][1], "%d");
strcat (GMT->current.plot.format[2][0], d_fmt[id]);
strcat (GMT->current.plot.format[2][1], d_fmt[id]);
if (GMT->current.setting.map_degree_symbol != gmt_none)
{ /* We want the degree symbol appended */
sprintf (fmt, "%c", (int)GMT->current.setting.ps_encoding.code[GMT->current.setting.map_degree_symbol]);
Expand Down
8 changes: 4 additions & 4 deletions src/gmt_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,17 +194,17 @@ struct GMT_DATE_IO {
};

struct GMT_GEO_IO { /* For geographic output and plotting */
double f_sec_to_int; /* Scale to convert 0.xxx seconds to integer xxx (used for formatting) */
double f_sec_to_int; /* Scale to convert 0.xxx seconds to integer xxx (used for formatting) */
unsigned int n_sec_decimals; /* Number of digits in decimal seconds (0 for whole seconds) */
unsigned int range; /* 0 for 0/360, 1 for -360/0, 2 for -180/+180 */
int wesn; /* 1 if we want sign encoded with suffix W, E, S, N, 2 if also want space before letter.
If negative -1 or -2 we place the suffix before the annotation and -2 with a space after. */
int order[3]; /* The relative order of degree, minute, seconds in form (-ve if unused) */
bool decimal; /* true if we want to use the FORMAT_FLOAT_OUT for decimal degrees only */
bool no_sign; /* true if we want absolute values (plot only) */
char x_format[GMT_LEN64]; /* Actual C format used to plot/output longitude */
char y_format[GMT_LEN64]; /* Actual C format used to plot/output latitude */
char delimiter[2][2]; /* Delimiter strings in date, e.g. "-" */
bool leading_zeros; /* True to get leading zeros in degrees */
char format[GMT_LEN64]; /* Actual C format used to output coordinate */
char delimiter[2][2]; /* Delimiter strings in date, e.g. "-" */
};

struct GMT_COL_INFO { /* Used by -i and input parsing */
Expand Down
24 changes: 12 additions & 12 deletions src/gmt_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -15791,7 +15791,7 @@ void gmtlib_get_annot_label (struct GMT_CTRL *GMT, double val, char *label, bool
int sign, d, m, s, m_sec;
unsigned int k, n_items, level, type;
bool zero_fix = false, lat_special = (lonlat == 3), deg_special = (lonlat == 4);
char hemi_pre[GMT_LEN16] = {""}, hemi_post[GMT_LEN16] = {""}, text[GMT_LEN64] = {""};
char hemi_pre[GMT_LEN16] = {""}, hemi_post[GMT_LEN16] = {""}, text[GMT_LEN64] = {""}, *use_format = NULL;

/* Must override do_minutes and/or do_seconds if format uses decimal notation for that item */

Expand All @@ -15801,11 +15801,9 @@ void gmtlib_get_annot_label (struct GMT_CTRL *GMT, double val, char *label, bool

if (lat_special) lonlat = 1; /* Remove the special flag */
if (deg_special) lonlat = 0; /* Remove the special flag */
if (lonlat == 0) { /* Fix longitudes range first */
if (lonlat == 0) /* Fix longitudes range first */
gmt_lon_range_adjust (GMT->current.plot.calclock.geo.range, &val);
}

if (lonlat) { /* i.e., for geographical data */
else { /* i.e., for geographical data */
if (doubleAlmostEqual (val, 360.0) && !worldmap)
val = 0.0;
if (doubleAlmostEqual (val, 360.0) && worldmap && GMT->current.proj.projection_GMT == GMT_OBLIQUE_MERC)
Expand Down Expand Up @@ -15854,32 +15852,34 @@ void gmtlib_get_annot_label (struct GMT_CTRL *GMT, double val, char *label, bool
if (!(lat_special || deg_special) && GMT->current.plot.r_theta_annot && lonlat) /* Special check for the r in r-theta [set via -Jp|P +fe modifier] */
gmt_sprintf_float (GMT, label, GMT->current.setting.format_float_map, val);
else if (GMT->current.plot.calclock.geo.decimal)
sprintf (label, GMT->current.plot.calclock.geo.x_format, val, hemi_post);
sprintf (label, GMT->current.plot.calclock.geo.format, val, hemi_post);
else {
(void) gmtlib_geo_to_dms (val, n_items, GMT->current.plot.calclock.geo.f_sec_to_int, &d, &m, &s, &m_sec); /* Break up into d, m, s, and remainder */
if (d == 0 && sign == -1) { /* Must write out -0 degrees, do so by writing -1 and change 1 to 0 */
d = -1;
zero_fix = true;
}
if (hemi_pre[0]) strcpy (label, hemi_pre);
use_format = (lonlat & 1 ? gmt_strrep (GMT->current.plot.format[level][type], "%3.3d", "%2.2d") :strdup (GMT->current.plot.format[level][type]));

switch (2*level+type) {
case 0:
sprintf (text, GMT->current.plot.format[level][type], d, hemi_post);
sprintf (text, use_format, d, hemi_post);
break;
case 1:
sprintf (text, GMT->current.plot.format[level][type], d, m_sec, hemi_post);
sprintf (text, use_format, d, m_sec, hemi_post);
break;
case 2:
sprintf (text, GMT->current.plot.format[level][type], d, m, hemi_post);
sprintf (text, use_format, d, m, hemi_post);
break;
case 3:
sprintf (text, GMT->current.plot.format[level][type], d, m, m_sec, hemi_post);
sprintf (text, use_format, d, m, m_sec, hemi_post);
break;
case 4:
sprintf (text, GMT->current.plot.format[level][type], d, m, s, hemi_post);
sprintf (text, use_format, d, m, s, hemi_post);
break;
case 5:
sprintf (text, GMT->current.plot.format[level][type], d, m, s, m_sec, hemi_post);
sprintf (text, use_format, d, m, s, m_sec, hemi_post);
break;
}
if (zero_fix) text[1] = '0'; /* Undo the fix above */
Expand Down

0 comments on commit 4d392a4

Please sign in to comment.