22 #include "utils/builtins.h"
24 #include "../postgis_config.h"
26 #include "lwgeom_transform.h"
31 #define MARC21_NS ((char *) "http://www.loc.gov/MARC21/slim")
58 text *format_text_input = PG_GETARG_TEXT_P(1);
59 const char *format = text_to_cstring(format_text_input);
65 PG_FREE_IF_COPY(gs, 0);
66 lwpgerror(
"ST_AsMARC21: Input geometry has unknown (%d) SRID", srid);
71 if (lwproj_lookup(srid, srid, &lwproj) ==
LW_FAILURE) {
73 PG_FREE_IF_COPY(gs, 0);
74 lwpgerror(
"ST_AsMARC21: Failure reading projections from spatial_ref_sys.");
95 if (!lwproj_is_latlong(lwproj)) {
97 PG_FREE_IF_COPY(gs, 0);
98 lwpgerror(
"ST_AsMARC21: Unsupported SRID (%d). Only lon/lat coordinate systems are supported in MARC21/XML Documents.", srid);
106 if (marc21) PG_RETURN_TEXT_P(marc21);
123 POSTGIS_DEBUG(3,
"creating stringbuffer");
142 for (uint32_t i = 0; i < coll->
ngeoms; i++) {
182 POSTGIS_DEBUG(3,
" closing MARC21/XML record");
201 char *dec_part = strchr(format,
'.');
202 if(!dec_part) dec_part = strchr(format,
',');
206 if (strcmp(format,
"hdddmmss") && strcmp(format,
"dddmmss")) {
214 if(strlen(dec_part)<2)
return LW_FALSE;
216 int_part = palloc(
sizeof(
char)*strlen(format));
217 memcpy(int_part, &format[0], strlen(format) - strlen(dec_part));
218 int_part[strlen(format) - strlen(dec_part)]=
'\0';
220 if (strcmp(int_part,
"hddd") && strcmp(int_part,
"ddd") &&
221 strcmp(int_part,
"hdddmm") && strcmp(int_part,
"dddmm") &&
222 strcmp(int_part,
"hdddmmss") && strcmp(int_part,
"dddmmss")) {
229 for (
size_t i = 1; i < strlen(dec_part); i++) {
231 if(dec_part[i]!=int_part[strlen(int_part)-1]) {
248 char cardinal_direction;
249 char decimal_separator;
251 int degrees = (int) decimal_degrees;
252 double minutes = fabs((decimal_degrees-degrees)*60);
253 double seconds = fabs((minutes-(
int)minutes) *60);
255 int has_cardinal_direction = 0;
256 int num_decimals = 0;
257 char*
res = palloc(
sizeof(
char)*strlen(format)+2);
269 POSTGIS_DEBUGF(2,
"corner_to_subfield_sb called with coordinates: %f and format: %s",decimal_degrees,format);
271 if((
int)(seconds + 0.5)>=60) {
273 seconds = seconds-60;
274 minutes = minutes +1;
279 if(strchr(format,
'.')) {
280 num_decimals = strlen(strchr(format,
'.'))-1;
281 decimal_separator =
'.';
284 if(strchr(format,
',')) {
285 num_decimals = strlen(strchr(format,
','))-1;
286 decimal_separator =
',';
291 has_cardinal_direction = 1;
293 if(subfield==
'd'||subfield==
'e'){
295 if(decimal_degrees>0){
297 cardinal_direction=
'E';
301 cardinal_direction=
'W';
302 degrees=abs(degrees);
303 decimal_degrees= fabs(decimal_degrees);
308 if(subfield==
'f'||subfield==
'g'){
310 if(decimal_degrees>0){
312 cardinal_direction=
'N';
316 cardinal_direction=
'S';
317 degrees=abs(degrees);
318 decimal_degrees= fabs(decimal_degrees);
326 if(format[3+has_cardinal_direction]==
'.' || format[3+has_cardinal_direction]==
',' ) {
332 int pad_degrees = (int)strlen(format);
334 if(decimal_degrees <0 && decimal_degrees>-100) pad_degrees=strlen(format)+1;
336 if(has_cardinal_direction) pad_degrees=pad_degrees-1;
338 snprintf(
res,
buffer_size,
"%0*.*f",pad_degrees,num_decimals,decimal_degrees);
341 }
else if(format[5+has_cardinal_direction]==
'.' || format[5+has_cardinal_direction]==
',' ) {
348 if(minutes<10) pad_minutes = (int)strlen(format)-has_cardinal_direction-3;
350 snprintf(
res,
buffer_size,
"%.3d%0*.*f",degrees,pad_minutes,num_decimals,fabs(minutes));
354 else if(format[7+has_cardinal_direction]==
'.' || format[7+has_cardinal_direction]==
',') {
362 if(seconds<10) pad_seconds = (int) strlen(format)-has_cardinal_direction-5;
364 snprintf(
res,
buffer_size,
"%.3d%.2d%0*.*f",degrees,(
int)minutes,pad_seconds,num_decimals,fabs(seconds));
372 snprintf(
res,
buffer_size,
"%.3d%.2d%.2d",degrees,(
int)minutes,(
int)(seconds + 0.5));
377 if(decimal_separator==
','){
379 res[strlen(
res)-num_decimals-1] =
',';
383 if(has_cardinal_direction){
403 POSTGIS_DEBUG(2,
"gbox_to_marc21_sb called");
413 POSTGIS_DEBUG(2,
"=> gbox_to_marc21_sb returns LW_SUCCESS");
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM can contain sub-geometries or not.
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
#define LW_TRUE
Return types for functions with status returns.
#define SRID_UNKNOWN
Unknown SRID value.
This library is the generic geometry handling section of PostGIS.
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
lwvarlena_t * lwgeom_to_marc21(const LWGEOM *geom, const char *format)
static int corner_to_subfield_sb(stringbuffer_t *sb, double decimal_degrees, const char *format, char subfield)
static int gbox_to_marc21_sb(const GBOX box, const char *format, stringbuffer_t *sb)
PG_FUNCTION_INFO_V1(ST_AsMARC21)
static int is_format_valid(const char *format)
Datum ST_AsMARC21(PG_FUNCTION_ARGS)
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
int stringbuffer_aprintf(stringbuffer_t *s, const char *fmt,...)
Appends a formatted string to the current string buffer, using the format and argument list provided.
lwvarlena_t * stringbuffer_getvarlenacopy(stringbuffer_t *s)
stringbuffer_t * stringbuffer_create(void)
Allocate a new stringbuffer_t.
void stringbuffer_destroy(stringbuffer_t *s)
Free the stringbuffer_t and all memory managed within it.