PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ parse_geo_literal()

static double parse_geo_literal ( char *  literal)
static

Coordinate formats supported (from the MARC21/XML documentation):

-> hdddmmss (hemisphere-degrees-minutes-seconds) -> hddd.dddddd (hemisphere-degrees.decimal degrees) -> +-ddd.dddddd (hemisphere[+/-]-degrees.decimal degrees) (“+” for N and E, “-“ for S and W; the plus sign is optional) -> hdddmm.mmmm (hemisphere-degrees-minutes.decimal minutes): -> hdddmmss.sss (hemisphere-degrees-minutes-seconds.decimal seconds)

degrees/minutes/seconds: hdddmmss (hemisphere-degrees-minutes-seconds) Ex. 0793235 +0793235 E0793235 || | |-> seconds (2 digits; left padded with 0) || |-> minutes (2 digits; left padded with 0) ||-> degrees (3 digits; left padded with 0) |-> start_literal (1 digit; optional)

decimal degrees: hddd.dddddd (hemisphere-degrees.decimal degrees) Ex. E079.533265 +079.533265 || |-> indicates decimal degrees ||-> degrees (3 digits; left padded with 0) |-> start_literal (1 digit; optional)

decimal minutes: hdddmm.mmmm (cardinal direction|degrees|minutes.decimal minutes) Ex. E07932.5332 || | |-> indicates decimal minutes || |-> minutes (2 digits; left padded with 0) ||-> degrees (3 digits; left padded with 0) |-> start_literal (1 digit; optional)

decimal seconds: hdddmmss.sss (hemisphere-degrees-minutes-seconds.decimal seconds) Ex. E0793235.575 || | | |-> indicates decimal seconds || | |-> seconds (2 digits; left padded with 0) || |-> minutes (2 digits; left padded with 0) ||-> degrees (3 digits; left padded with 0) |-> start_literal (1 digit; optional)

“+” for N and E (the plus sign is optional) “-“ for S and W

Definition at line 171 of file lwgeom_in_marc21.c.

171  {
172 
185  char *dgr;
186  char *min;
187  char *sec;
188  size_t literal_length;
189 
190  char start_character = literal[0];
191  int start_literal = 0;
192  double result = 0.0;
193 
194  const size_t numdigits_degrees = 3;
195  const size_t numdigits_minutes = 2;
196  const size_t numdigits_seconds = 2;
197 
198  POSTGIS_DEBUGF(2, "parse_geo_literal called (%s)", literal);
199  POSTGIS_DEBUGF(2, " start character: %c", start_character);
200 
201  literal_length = strlen(literal);
202 
203  if (!isdigit(start_character)) start_literal = 1;
204 
205  POSTGIS_DEBUGF(2, " start_literal=%d", start_literal);
206 
207  dgr = palloc(sizeof(char)*numdigits_degrees+1);
208  snprintf(dgr, numdigits_degrees+1, "%s", &literal[start_literal]);
209 
210  if (strchr(literal, '.') == NULL && strchr(literal, ',') == NULL) {
211 
223  POSTGIS_DEBUG(2, " lat/lon integer coordinates detected");
224  POSTGIS_DEBUGF(2, " parsed degrees (lon/lat): %s", dgr);
225 
226  /* literal contain at least degrees.
227  * minutes and seconds are optional */
228  result = atof(dgr);
229 
230  /* checks if the literal contains minutes */
231  if (literal_length > (start_literal + numdigits_degrees)) {
232 
233  min = palloc(sizeof(char)*numdigits_minutes+1);
234  snprintf(min, numdigits_minutes+1, "%s", &literal[start_literal+numdigits_degrees]);
235  POSTGIS_DEBUGF(2, " parsed minutes (lon/lat): %s", min);
236  result = result + atof(min) / 60;
237  pfree(min);
238 
239  /* checks if the literal contains seconds */
240  if (literal_length >= (start_literal + numdigits_degrees + numdigits_minutes)) {
241 
242  sec = palloc(sizeof(char)*numdigits_seconds+1);
243  snprintf(sec, numdigits_seconds+1, "%s", &literal[start_literal+numdigits_degrees+numdigits_minutes]);
244  POSTGIS_DEBUGF(2, " parsed seconds (lon/lat): %s", sec);
245 
246  result = result + atof(sec) / 3600;
247  pfree(sec);
248 
249  }
250 
251 
252  }
253 
254 
255  } else {
256 
257  POSTGIS_DEBUG(2, " decimal coordinates detected");
258 
259  if (strchr(literal, ',')) {
260 
261  /* changes the literal decimal sign from comma to period to avoid problems with atof.
262  * from the docs "In MARC21/XML coordinates, the decimal sign may be either a period or a comma." */
263 
264  literal[literal_length-strlen(strchr(literal, ','))]='.';
265  POSTGIS_DEBUGF(2, " decimal separator changed to '.': %s",literal);
266 
267  }
268 
269  /* checks if the literal is encoded in decimal degrees */
270  if (literal[start_literal + numdigits_degrees] == '.') {
271 
281  char *dec = palloc(sizeof(char)*literal_length+1);
282  snprintf(dec, literal_length+1, "%s", &literal[start_literal]);
283  result = atof(dec);
284 
285  POSTGIS_DEBUGF(2, " parsed decimal degrees: %s", dec);
286  pfree(dec);
287 
288  /* checks if the literal is encoded in decimal minutes */
289  } else if (literal[start_literal + numdigits_degrees + numdigits_minutes] == '.') {
290 
300  size_t len_decimal_minutes = literal_length - (start_literal + numdigits_degrees);
301 
302  min = palloc(sizeof(char)*len_decimal_minutes+1);
303  snprintf(min, len_decimal_minutes+1, "%s", &literal[start_literal + numdigits_degrees]);
304 
305  POSTGIS_DEBUGF(2, " parsed degrees: %s", dgr);
306  POSTGIS_DEBUGF(2, " parsed decimal minutes: %s", min);
307 
308  result = atof(dgr) + (atof(min) / 60);
309 
310  pfree(min);
311 
312  /* checks if the literal is encoded in decimal seconds */
313  } else if (literal[start_literal + numdigits_degrees + numdigits_minutes + numdigits_seconds] == '.') {
314 
325  size_t len_decimal_seconds = literal_length - (start_literal + numdigits_degrees + numdigits_minutes);
326 
327  min = palloc(sizeof(char)*numdigits_minutes+1);
328  snprintf(min, numdigits_minutes+1, "%s", &literal[start_literal + numdigits_degrees]);
329 
330  sec = palloc(sizeof(char)*len_decimal_seconds+1);
331  snprintf(sec, len_decimal_seconds+1, "%s", &literal[start_literal + numdigits_degrees + numdigits_minutes]);
332 
333  result = atof(dgr) + (atof(min) / 60) + (atof(sec) / 3600);
334 
335  POSTGIS_DEBUGF(2, " parsed degrees: %s", dgr);
336  POSTGIS_DEBUGF(2, " parsed minutes: %s", min);
337  POSTGIS_DEBUGF(2, " parsed decimal seconds: %s", sec);
338  pfree(min);
339  pfree(sec);
340 
341  }
342 
343  }
344 
350  pfree(dgr);
351 
352  if (start_character == 'S' || start_character == 'W' || start_character == '-') {
353 
354  POSTGIS_DEBUGF(2, " switching sign due to start character: '%c'", start_character);
355  result = -result;
356 
357  }
358 
359  POSTGIS_DEBUGF(2, "=> parse_geo_literal returns: %.*f (in decimal degrees)", literal_length-(3+start_literal), result);
360  return result;
361 }
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:262

References result.

Referenced by parse_marc21().

Here is the caller graph for this function: