diff --git a/expected/bounding_box_gist_2.out b/expected/bounding_box_gist_2.out new file mode 100644 index 0000000..9a6789b --- /dev/null +++ b/expected/bounding_box_gist_2.out @@ -0,0 +1,240 @@ +SET enable_seqscan=true; +CREATE TABLE bbox_ellipse (e sellipse not null); +INSERT INTO bbox_ellipse VALUES ('<{10d, 0.1d}, (0d,0d), 0d>'); +SELECT spoint '(5d, 0d)' @ sellipse '<{10d, 0.1d}, (0d,0d), 0d>' AS inside; + inside +-------- + t +(1 row) + +SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' @ e; + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' <@ e; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' @ e; + QUERY PLAN +----------------------------------------------------------- + Aggregate + -> Seq Scan on bbox_ellipse + Filter: ('(0.08726646259971647 , 0)'::spoint @ e) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' <@ e; + QUERY PLAN +------------------------------------------------------------ + Aggregate + -> Seq Scan on bbox_ellipse + Filter: ('(0.08726646259971647 , 0)'::spoint <@ e) +(3 rows) + +-- The ellipse has semi-major axis length of 10 degrees along the equator, +-- so (lon,lat) = (5,0) should be inside. +CREATE INDEX idx_bbox_ellipse ON bbox_ellipse USING gist (e); +ANALYZE bbox_ellipse; +SET enable_seqscan=false; +SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' @ e; + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' <@ e; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' @ e; + QUERY PLAN +--------------------------------------------------------------- + Aggregate + -> Index Scan using idx_bbox_ellipse on bbox_ellipse + Index Cond: (e ~ '(0.08726646259971647 , 0)'::spoint) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_ellipse WHERE spoint '(5d, 0d)' <@ e; + QUERY PLAN +---------------------------------------------------------------- + Aggregate + -> Index Scan using idx_bbox_ellipse on bbox_ellipse + Index Cond: (e @> '(0.08726646259971647 , 0)'::spoint) +(3 rows) + +SET enable_seqscan=true; +CREATE TABLE bbox_poly (p spoly not null); +INSERT INTO bbox_poly VALUES ('{(40d,-40d), (0d,80d), (-40d,-40d)}'); +SELECT spoint '(0d, 0d)' @ spoly '{(40d,-40d), (0d,80d), (-40d,-40d)}' AS inside; + inside +-------- + t +(1 row) + +SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' @ p; + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' <@ p; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' @ p; + QUERY PLAN +----------------------------------------- + Aggregate + -> Seq Scan on bbox_poly + Filter: ('(0 , 0)'::spoint @ p) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' <@ p; + QUERY PLAN +------------------------------------------ + Aggregate + -> Seq Scan on bbox_poly + Filter: ('(0 , 0)'::spoint <@ p) +(3 rows) + +CREATE INDEX idx_bbox_poly ON bbox_poly USING gist (p); +ANALYZE bbox_poly; +SET enable_seqscan=false; +SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' @ p; + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' <@ p; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' @ p; + QUERY PLAN +--------------------------------------------------- + Aggregate + -> Index Scan using idx_bbox_poly on bbox_poly + Index Cond: (p ~ '(0 , 0)'::spoint) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_poly WHERE spoint '(0d, 0d)' <@ p; + QUERY PLAN +--------------------------------------------------- + Aggregate + -> Index Scan using idx_bbox_poly on bbox_poly + Index Cond: (p @> '(0 , 0)'::spoint) +(3 rows) + +SET enable_seqscan=true; +CREATE TABLE bbox_path (p spath not null); +INSERT INTO bbox_path VALUES ('{(-46d,0d), (-45d,80d), (-45d,0d), (80d,0d)}'); +SELECT sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && spath '{(-46d,0d), (-45d,80d), (-45d,0d), (80d,0d)}' AS crossing; + crossing +---------- + t +(1 row) + +SELECT spoint '(0d, 0d)' @ spath '{(-46d,0d), (-45d,80d), (-45d,0d), (80d,0d)}' AS inside; + inside +-------- + t +(1 row) + +SELECT COUNT(*) FROM bbox_path WHERE sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && p; + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' @ p; + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' <@ p; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && p; + QUERY PLAN +--------------------------------------------------------------------------------------------------------- + Aggregate + -> Seq Scan on bbox_path + Filter: ('( 6.1086523819801535, 1.5707963267948966, 0, ZXZ ), 0.34906585039886584'::sline && p) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' @ p; + QUERY PLAN +----------------------------------------- + Aggregate + -> Seq Scan on bbox_path + Filter: ('(0 , 0)'::spoint @ p) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' <@ p; + QUERY PLAN +------------------------------------------ + Aggregate + -> Seq Scan on bbox_path + Filter: ('(0 , 0)'::spoint <@ p) +(3 rows) + +CREATE INDEX idx_bbox_path ON bbox_path USING gist (p); +ANALYZE bbox_path; +SET enable_seqscan=false; +SELECT COUNT(*) FROM bbox_path WHERE sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && p; + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' @ p; + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' <@ p; + count +------- + 1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE sline(spoint '(0d, -10d)', spoint '(0d, 10d)') && p; + QUERY PLAN +------------------------------------------------------------------------------------------------------------- + Aggregate + -> Index Scan using idx_bbox_path on bbox_path + Index Cond: (p && '( 6.1086523819801535, 1.5707963267948966, 0, ZXZ ), 0.34906585039886584'::sline) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' @ p; + QUERY PLAN +--------------------------------------------------- + Aggregate + -> Index Scan using idx_bbox_path on bbox_path + Index Cond: (p ~ '(0 , 0)'::spoint) +(3 rows) + +EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM bbox_path WHERE spoint '(0d, 0d)' <@ p; + QUERY PLAN +--------------------------------------------------- + Aggregate + -> Index Scan using idx_bbox_path on bbox_path + Index Cond: (p @> '(0 , 0)'::spoint) +(3 rows) + diff --git a/expected/epochprop_1.out b/expected/epochprop_1.out new file mode 100644 index 0000000..b679287 --- /dev/null +++ b/expected/epochprop_1.out @@ -0,0 +1,107 @@ +SELECT + to_char(DEGREES(tp[1]), '999D9999999999'), + to_char(DEGREES(tp[2]), '999D9999999999'), + to_char(tp[3], '999D999'), + to_char(DEGREES(tp[4])*3.6e6, '999D999'), + to_char(DEGREES(tp[5])*3.6e6, '99999D999'), + to_char(tp[6], '999D999') +FROM ( + SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), + 546.9759, + RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, + -100) AS tp) AS q; + to_char | to_char | to_char | to_char | to_char | to_char +-----------------+-----------------+----------+----------+------------+---------- + 269.4742714391 | 4.4072939987 | 543.624 | -791.442 | 10235.412 | -110.450 +(1 row) + +SELECT + to_char(DEGREES(tp[1]), '999D9999999999'), + to_char(DEGREES(tp[2]), '999D9999999999'), + to_char(tp[3], '999D999'), + to_char(DEGREES(tp[4])*3.6e6, '999D999'), + to_char(DEGREES(tp[5])*3.6e6, '99999D999'), + to_char(tp[6], '999D999') +FROM ( + SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), + 0, + RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, + -100) AS tp) AS q; + to_char | to_char | to_char | to_char | to_char | to_char +-----------------+-----------------+---------+----------+------------+--------- + 269.4744079540 | 4.4055337210 | | -801.210 | 10361.762 | +(1 row) + +SELECT + to_char(DEGREES(tp[1]), '999D9999999999'), + to_char(DEGREES(tp[2]), '999D9999999999'), + to_char(tp[3], '999D999'), + to_char(DEGREES(tp[4])*3.6e6, '999D999'), + to_char(DEGREES(tp[5])*3.6e6, '99999D999'), + to_char(tp[6], '999D999') +FROM ( + SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), + NULL, + RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, + -100) AS tp) AS q; + to_char | to_char | to_char | to_char | to_char | to_char +-----------------+-----------------+---------+----------+------------+--------- + 269.4744079540 | 4.4055337210 | | -801.210 | 10361.762 | +(1 row) + +SELECT + to_char(DEGREES(tp[1]), '999D9999999999'), + to_char(DEGREES(tp[2]), '999D9999999999'), + to_char(tp[3], '999D999'), + to_char(DEGREES(tp[4])*3.6e6, '999D999'), + to_char(DEGREES(tp[5])*3.6e6, '99999D999'), + to_char(tp[6], '999D999') +FROM ( + SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), + 23, + RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), NULL, + 20) AS tp) AS q; + to_char | to_char | to_char | to_char | to_char | to_char +-----------------+-----------------+----------+----------+------------+---------- + 269.4476085384 | 4.7509315989 | 23.000 | -801.617 | 10361.984 | 2.159 +(1 row) + +SELECT + to_char(DEGREES(tp[1]), '999D9999999999'), + to_char(DEGREES(tp[2]), '999D9999999999'), + to_char(tp[3], '999D999'), + to_char(DEGREES(tp[4])*3.6e6, '999D999'), + to_char(DEGREES(tp[5])*3.6e6, '99999D999'), + to_char(tp[6], '999D999') +FROM ( + SELECT epoch_prop(spoint(radians(269.45207695), radians(4.693364966)), + 23, + NULL, RADIANS(10362/3.6e6), -110, + 120) AS tp) AS q; + to_char | to_char | to_char | to_char | to_char | to_char +-----------------+-----------------+----------+----------+------------+---------- + 269.4520769500 | 5.0388680565 | 23.007 | -.000 | 10368.061 | -97.120 +(1 row) + +SELECT epoch_prop(NULL, + 23, + 0.01 , RADIANS(10362/3.6e6), -110, + 120); +ERROR: NULL position not supported in epoch propagation +SELECT epoch_prop_pos(spoint(radians(269.45207695), radians(4.693364966)), + 23, + RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), -110, + 20) AS tp; + tp +------------------------------------------- + (4.702747926583129 , 0.08291945093459933) +(1 row) + +SELECT epoch_prop_pos(spoint(radians(269.45207695), radians(4.693364966)), + RADIANS(-801.551/3.6e6), RADIANS(10362/3.6e6), + 20) AS tp; + tp +------------------------------------------- + (4.702747930619516 , 0.08291939893808763) +(1 row) + diff --git a/src/output.c b/src/output.c index 7598d46..7df5889 100644 --- a/src/output.c +++ b/src/output.c @@ -1,5 +1,12 @@ #include "types.h" +#if PG_VERSION_NUM >= 120000 +#include "utils/float.h" +#include "common/shortest_dec.h" +#endif + +#include + #if !defined(PGSPHERE_VERSION) #error "PGSPHERE_VERSION macro is not set" #endif @@ -9,7 +16,6 @@ /* Output functions */ - /* Output modes */ #define OUTPUT_RAD 1 /* output in radians */ #define OUTPUT_DEG 2 /* output in degrees */ @@ -25,7 +31,7 @@ static unsigned char sphere_output = OUTPUT_RAD; /* * Defines the precision of floating point values in output. */ -static int sphere_output_precision = DBL_DIG; +static int sphere_output_precision = INT_MAX; PG_FUNCTION_INFO_V1(set_sphere_output); PG_FUNCTION_INFO_V1(spherepoint_out); @@ -37,6 +43,7 @@ PG_FUNCTION_INFO_V1(spherepath_out); PG_FUNCTION_INFO_V1(sphereellipse_out); PG_FUNCTION_INFO_V1(spherebox_out); PG_FUNCTION_INFO_V1(set_sphere_output_precision); +PG_FUNCTION_INFO_V1(reset_sphere_output_precision); PG_FUNCTION_INFO_V1(pg_sphere_version); /* @@ -94,6 +101,8 @@ Datum spherebox_out(PG_FUNCTION_ARGS); */ Datum pg_sphere_version(PG_FUNCTION_ARGS); +static void +spheretrans_out_buffer(StringInfo si, const SEuler *se); /* * Converts radians to DEG ( degrees, minutes, seconds ) @@ -128,6 +137,116 @@ rad_to_dms(double rad, unsigned int *deg, unsigned int *min, double *sec) } } +static void +pgs_strinfo_put_chr(StringInfo si, char c) +{ + appendStringInfoChar(si, c); +} + +static void +pgs_strinfo_put_str(StringInfo si, char *s) +{ + appendStringInfoString(si, s); +} + +static void +pgs_strinfo_put_d64(StringInfo si, double value) +{ + int cw, + ndig; + char buf[128]; + +#if PG_VERSION_NUM >= 120000 + + if (extra_float_digits > 0) + { + cw = double_to_shortest_decimal_buf(value, buf); + } + else + { + ndig = DBL_DIG + extra_float_digits; + if (ndig < 1) + ndig = 1; + + cw = pg_strfromd(buf, 128, ndig, value); + } + +#else + + ndig = DBL_DIG + extra_float_digits; + if (ndig < 1) + ndig = 1; + + cw = snprintf(buf, 128, "%.*g", ndig, value); + +#endif + + if (cw < 0) + { + fflush(stderr); + abort(); + } + + pgs_strinfo_put_str(si, buf); +} + +static void +pgs_strinfo_put_lng_dms(StringInfo si, double lng) +{ + unsigned int lngdeg, + lngmin; + double lngsec; + + rad_to_dms(lng, &lngdeg, &lngmin, &lngsec); + + appendStringInfo(si, "%3ud %2um ", lngdeg, lngmin); + pgs_strinfo_put_d64(si, lngsec); + pgs_strinfo_put_chr(si, 's'); +} + +static void +pgs_strinfo_put_lng_hms(StringInfo si, double lng) +{ + unsigned int lnghour, + lngmin; + double lngsec; + + rad_to_dms(lng / 15.0, &lnghour, &lngmin, &lngsec); + + appendStringInfo(si, "%3uh %2um ", lnghour, lngmin); + pgs_strinfo_put_d64(si, lngsec); + pgs_strinfo_put_chr(si, 's'); +} + +static void +pgs_strinfo_put_lat_dms(StringInfo si, double lat) +{ + unsigned int latdeg, + latmin; + double latsec; + const char latsign = lat >= 0 ? '+' : '-'; + + rad_to_dms(lat, &latdeg, &latmin, &latsec); + + appendStringInfo(si, "%c%2ud %2um ", latsign, latdeg, latmin); + pgs_strinfo_put_d64(si, latsec); + pgs_strinfo_put_chr(si, 's'); +} + +static void +pgs_strinfo_put_radius_dms(StringInfo si, double radius) +{ + unsigned int rdeg, + rmin; + double rsec; + + rad_to_dms(radius, &rdeg, &rmin, &rsec); + + appendStringInfo(si, "%2ud %2um ", rdeg, rmin); + pgs_strinfo_put_d64(si, rsec); + pgs_strinfo_put_chr(si, 's'); +} + Datum set_sphere_output_precision(PG_FUNCTION_ARGS) { @@ -144,6 +263,18 @@ set_sphere_output_precision(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(buf); } +Datum +reset_sphere_output_precision(PG_FUNCTION_ARGS) +{ + char *buf = (char *) palloc(20); + + sphere_output_precision = INT_MAX; + + sprintf(buf, "RESET"); + + PG_RETURN_CSTRING(buf); +} + Datum set_sphere_output(PG_FUNCTION_ARGS) { @@ -176,8 +307,8 @@ set_sphere_output(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(buf); } -Datum -spherepoint_out(PG_FUNCTION_ARGS) +static Datum +spherepoint_out_compat(PG_FUNCTION_ARGS) { SPoint *sp = (SPoint *) PG_GETARG_POINTER(0); char *buffer = (char *) palloc(255); @@ -227,11 +358,89 @@ spherepoint_out(PG_FUNCTION_ARGS) } PG_RETURN_CSTRING(buffer); +} + +static void +spherepoint_out_deg(StringInfo si, const SPoint *sp) +{ + pgs_strinfo_put_chr(si, '('); + pgs_strinfo_put_d64(si, RADIANS * sp->lng); + pgs_strinfo_put_str(si, "d, "); + pgs_strinfo_put_d64(si, RADIANS * sp->lat); + pgs_strinfo_put_str(si, "d)"); +} +static void +spherepoint_out_rad(StringInfo si, const SPoint *sp) +{ + pgs_strinfo_put_chr(si, '('); + pgs_strinfo_put_d64(si, sp->lng); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_d64(si, sp->lat); + pgs_strinfo_put_str(si, ")"); +} + +static void +spherepoint_out_dms(StringInfo si, const SPoint *sp) +{ + pgs_strinfo_put_chr(si, '('); + pgs_strinfo_put_lng_dms(si, sp->lng); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_lat_dms(si, sp->lat); + pgs_strinfo_put_chr(si, ')'); +} + +static void +spherepoint_out_hms(StringInfo si, const SPoint *sp) +{ + pgs_strinfo_put_chr(si, '('); + pgs_strinfo_put_lng_hms(si, sp->lng); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_lat_dms(si, sp->lat); + pgs_strinfo_put_chr(si, ')'); +} + +static inline void +spherepoint_out_buffer(StringInfo si, const SPoint *sp) +{ + switch (sphere_output) + { + case OUTPUT_DEG: + spherepoint_out_deg(si, sp); + break; + case OUTPUT_DMS: + spherepoint_out_dms(si, sp); + break; + case OUTPUT_HMS: + spherepoint_out_hms(si, sp); + break; + default: + spherepoint_out_rad(si, sp); + break; + } } Datum -spherecircle_out(PG_FUNCTION_ARGS) +spherepoint_out(PG_FUNCTION_ARGS) +{ + StringInfoData si; + SPoint *sp; + + if (sphere_output_precision != INT_MAX) + return spherepoint_out_compat(fcinfo); + + sp = (SPoint *) PG_GETARG_POINTER(0); + if (!sp) + PG_RETURN_NULL(); + + initStringInfo(&si); + spherepoint_out_buffer(&si, sp); + + PG_RETURN_CSTRING(si.data); +} + +static Datum +spherecircle_out_compat(PG_FUNCTION_ARGS) { SCIRCLE *c = (SCIRCLE *) PG_GETARG_POINTER(0); char *buffer = (char *) palloc(255); @@ -272,12 +481,86 @@ spherecircle_out(PG_FUNCTION_ARGS) } pfree(pointstr); + PG_RETURN_CSTRING(buffer); +} + +static void +spherecircle_out_deg(StringInfo si, const SCIRCLE *sc) +{ + pgs_strinfo_put_chr(si, '<'); + spherepoint_out_deg(si, &sc->center); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_d64(si, RADIANS * sc->radius); + pgs_strinfo_put_chr(si, '>'); +} +static void +spherecircle_out_rad(StringInfo si, const SCIRCLE *sc) +{ + pgs_strinfo_put_chr(si, '<'); + spherepoint_out_rad(si, &sc->center); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_d64(si, sc->radius); + pgs_strinfo_put_chr(si, '>'); +} + +static void +spherecircle_out_dms(StringInfo si, const SCIRCLE *sc) +{ + pgs_strinfo_put_chr(si, '<'); + spherepoint_out_dms(si, &sc->center); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_radius_dms(si, sc->radius); + pgs_strinfo_put_chr(si, '>'); +} + +static void +spherecircle_out_hms(StringInfo si, const SCIRCLE *sc) +{ + pgs_strinfo_put_chr(si, '<'); + spherepoint_out_hms(si, &sc->center); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_radius_dms(si, sc->radius); + pgs_strinfo_put_chr(si, '>'); } Datum -sphereellipse_out(PG_FUNCTION_ARGS) +spherecircle_out(PG_FUNCTION_ARGS) +{ + StringInfoData si; + SCIRCLE *sc; + + if (sphere_output_precision != INT_MAX) + return spherecircle_out_compat(fcinfo); + + sc = (SCIRCLE *) PG_GETARG_POINTER(0); + if (!sc) + PG_RETURN_NULL(); + + initStringInfo(&si); + + switch (sphere_output) + { + case OUTPUT_DEG: + spherecircle_out_deg(&si, sc); + break; + case OUTPUT_DMS: + spherecircle_out_dms(&si, sc); + break; + case OUTPUT_HMS: + spherecircle_out_hms(&si, sc); + break; + default: + spherecircle_out_rad(&si, sc); + break; + } + + PG_RETURN_CSTRING(si.data); +} + +static Datum +sphereellipse_out_compat(PG_FUNCTION_ARGS) { SELLIPSE *e = (SELLIPSE *) PG_GETARG_POINTER(0); char *buffer = (char *) palloc(255); @@ -333,8 +616,88 @@ sphereellipse_out(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(buffer); } +static void +sphereellipse_out_deg(StringInfo si, SELLIPSE *e) +{ + const SPoint sp = { e->psi, e->theta }; + + pgs_strinfo_put_str(si, "<{ "); + pgs_strinfo_put_d64(si, RADIANS * e->rad[0]); + pgs_strinfo_put_str(si, "d , "); + pgs_strinfo_put_d64(si, RADIANS * e->rad[1]); + pgs_strinfo_put_str(si, "d },"); + spherepoint_out_buffer(si, &sp); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_d64(si, RADIANS * e->phi); + pgs_strinfo_put_str(si, "d>"); +} + +static void +sphereellipse_out_rad(StringInfo si, SELLIPSE *e) +{ + const SPoint sp = { e->psi, e->theta }; + + pgs_strinfo_put_str(si, "<{ "); + pgs_strinfo_put_d64(si, e->rad[0]); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_d64(si, e->rad[1]); + pgs_strinfo_put_str(si, " },"); + spherepoint_out_buffer(si, &sp); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_d64(si, e->phi); + pgs_strinfo_put_str(si, ">"); +} + +static void +sphereellipse_out_dms(StringInfo si, SELLIPSE *e) +{ + const SPoint sp = { e->psi, e->theta }; + + pgs_strinfo_put_str(si, "<{ "); + pgs_strinfo_put_lng_dms(si, e->rad[0]); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_lng_dms(si, e->rad[1]); + pgs_strinfo_put_str(si, " },"); + spherepoint_out_buffer(si, &sp); + pgs_strinfo_put_str(si, " , "); + pgs_strinfo_put_lng_dms(si, e->phi); + pgs_strinfo_put_str(si, ">"); +} + Datum -sphereline_out(PG_FUNCTION_ARGS) +sphereellipse_out(PG_FUNCTION_ARGS) +{ + StringInfoData si; + SELLIPSE *e; + + if (sphere_output_precision != INT_MAX) + return sphereellipse_out_compat(fcinfo); + + e = (SELLIPSE *) PG_GETARG_POINTER(0); + if (!e) + PG_RETURN_NULL(); + + initStringInfo(&si); + + switch (sphere_output) + { + case OUTPUT_DEG: + sphereellipse_out_deg(&si, e); + break; + case OUTPUT_HMS: + case OUTPUT_DMS: + sphereellipse_out_dms(&si, e); + break; + default: + sphereellipse_out_rad(&si, e); + break; + } + + PG_RETURN_CSTRING(si.data); +} + +static Datum +sphereline_out_compat(PG_FUNCTION_ARGS) { SLine *sl = (SLine *) PG_GETARG_POINTER(0); char *out = (char *) palloc(255); @@ -384,7 +747,49 @@ sphereline_out(PG_FUNCTION_ARGS) } Datum -spheretrans_out(PG_FUNCTION_ARGS) +sphereline_out(PG_FUNCTION_ARGS) +{ + StringInfoData si; + SLine *sl; + SEuler se; + + if (sphere_output_precision != INT_MAX) + return sphereline_out_compat(fcinfo); + + sl = (SLine *) PG_GETARG_POINTER(0); + if (!sl) + PG_RETURN_NULL(); + + seuler_set_zxz(&se); + se.phi = sl->phi; + se.theta = sl->theta; + se.psi = sl->psi; + + initStringInfo(&si); + + pgs_strinfo_put_str(&si, "( "); + spheretrans_out_buffer(&si, &se); + pgs_strinfo_put_str(&si, " ), "); + + switch (sphere_output) + { + case OUTPUT_DEG: + pgs_strinfo_put_d64(&si, RADIANS * sl->length); + break; + case OUTPUT_HMS: + case OUTPUT_DMS: + pgs_strinfo_put_lng_dms(&si, sl->length); + break; + default: + pgs_strinfo_put_d64(&si, sl->length); + break; + } + + PG_RETURN_CSTRING(si.data); +} + +static Datum +spheretrans_out_compat(PG_FUNCTION_ARGS) { SEuler *se = (SEuler *) PG_GETARG_POINTER(0); char *buffer = (char *) palloc(255); @@ -469,8 +874,117 @@ spheretrans_out(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(buffer); } +static void +spheretrans_out_deg(StringInfo si, SPoint sp[3]) +{ + int i; + + for (i = 0; i < 3; ++i) + { + pgs_strinfo_put_d64(si, RADIANS * sp[i].lng); + pgs_strinfo_put_str(si, ", "); + } +} + +static void +spheretrans_out_rad(StringInfo si, SPoint sp[3]) +{ + int i; + + for (i = 0; i < 3; ++i) + { + pgs_strinfo_put_d64(si, sp[i].lng); + pgs_strinfo_put_str(si, ", "); + } +} + +static void +spheretrans_out_dms(StringInfo si, SPoint sp[3]) +{ + int i; + + for (i = 0; i < 3; ++i) + { + pgs_strinfo_put_lng_dms(si, sp[i].lng); + pgs_strinfo_put_str(si, ", "); + } +} + +static void +spheretrans_out_buffer(StringInfo si, const SEuler *se) +{ + SPoint val[3]; + unsigned char t[3]; + int i; + + val[0].lat = val[1].lat = val[2].lat = 0.0; + val[0].lng = se->phi; + val[1].lng = se->theta; + val[2].lng = se->psi; + + t[0] = se->phi_a; + t[1] = se->theta_a; + t[2] = se->psi_a; + + spoint_check(&val[0]); + spoint_check(&val[1]); + spoint_check(&val[2]); + + switch (sphere_output) + { + case OUTPUT_DEG: + spheretrans_out_deg(si, val); + break; + case OUTPUT_HMS: + case OUTPUT_DMS: + spheretrans_out_dms(si, val); + break; + default: + spheretrans_out_rad(si, val); + break; + } + + for (i = 0; i < 3; i++) + { + switch (t[i]) + { + case EULER_AXIS_X: + pgs_strinfo_put_chr(si, 'X'); + break; + case EULER_AXIS_Y: + pgs_strinfo_put_chr(si, 'Y'); + break; + case EULER_AXIS_Z: + pgs_strinfo_put_chr(si, 'Z'); + break; + default: + Assert(false); + } + } +} + Datum -spherepath_out(PG_FUNCTION_ARGS) +spheretrans_out(PG_FUNCTION_ARGS) +{ + StringInfoData si; + SEuler *se; + + if (sphere_output_precision != INT_MAX) + return spheretrans_out_compat(fcinfo); + + se = (SEuler *) PG_GETARG_POINTER(0); + if (!se) + PG_RETURN_NULL(); + + initStringInfo(&si); + + spheretrans_out_buffer(&si, se); + + PG_RETURN_CSTRING(si.data); +} + +static Datum +spherepath_out_compat(PG_FUNCTION_ARGS) { SPATH *path = PG_GETARG_SPATH(0); int32 i; @@ -494,7 +1008,37 @@ spherepath_out(PG_FUNCTION_ARGS) } Datum -spherepoly_out(PG_FUNCTION_ARGS) +spherepath_out(PG_FUNCTION_ARGS) +{ + StringInfoData si; + SPATH *path; + int32 i; + + if (sphere_output_precision != INT_MAX) + return spherepath_out_compat(fcinfo); + + path = PG_GETARG_SPATH(0); + if (!path) + PG_RETURN_NULL(); + + initStringInfo(&si); + + pgs_strinfo_put_chr(&si, '{'); + + for (i = 0; i < path->npts; ++i) + { + if (i > 0) + pgs_strinfo_put_chr(&si, ','); + spherepoint_out_buffer(&si, &path->p[i]); + } + + pgs_strinfo_put_chr(&si, '}'); + + PG_RETURN_CSTRING(si.data); +} + +static Datum +spherepoly_out_compat(PG_FUNCTION_ARGS) { SPOLY *poly = PG_GETARG_SPOLY(0); int32 i; @@ -518,7 +1062,37 @@ spherepoly_out(PG_FUNCTION_ARGS) } Datum -spherebox_out(PG_FUNCTION_ARGS) +spherepoly_out(PG_FUNCTION_ARGS) +{ + StringInfoData si; + SPOLY *poly; + int32 i; + + if (sphere_output_precision != INT_MAX) + return spherepoly_out_compat(fcinfo); + + poly = PG_GETARG_SPOLY(0); + if (!poly) + PG_RETURN_NULL(); + + initStringInfo(&si); + + pgs_strinfo_put_chr(&si, '{'); + + for (i = 0; i < poly->npts; ++i) + { + if (i > 0) + pgs_strinfo_put_chr(&si, ','); + spherepoint_out_buffer(&si, &poly->p[i]); + } + + pgs_strinfo_put_chr(&si, '}'); + + PG_RETURN_CSTRING(si.data); +} + +static Datum +spherebox_out_compat(PG_FUNCTION_ARGS) { SBOX *box = (SBOX *) PG_GETARG_POINTER(0); char *buffer = (char *) palloc(255); @@ -535,6 +1109,30 @@ spherebox_out(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(buffer); } +Datum +spherebox_out(PG_FUNCTION_ARGS) +{ + StringInfoData si; + SBOX *box; + + if (sphere_output_precision != INT_MAX) + return spherebox_out_compat(fcinfo); + + box = (SBOX *) PG_GETARG_POINTER(0); + if (!box) + PG_RETURN_NULL(); + + initStringInfo(&si); + + pgs_strinfo_put_chr(&si, '('); + spherepoint_out_buffer(&si, &box->sw); + pgs_strinfo_put_str(&si, ", "); + spherepoint_out_buffer(&si, &box->ne); + pgs_strinfo_put_chr(&si, ')'); + + PG_RETURN_CSTRING(si.data); +} + Datum pg_sphere_version(PG_FUNCTION_ARGS) {