From f5b83effaa5150d18960770c2ab195621ad7ed07 Mon Sep 17 00:00:00 2001 From: stepan-neretin7 Date: Mon, 24 Jul 2023 10:22:23 +0700 Subject: [PATCH] [ISSUE #16] Implemented a function and tests to extract vertices from spoly by index --- doc/functions.sgm | 89 ++++++++++++++++++- expected/init_test.out.in | 14 +-- expected/init_test_healpix.out.in | 4 +- expected/path.out | 25 ++++++ expected/poly.out | 30 +++++++ pgs_path.sql.in | 8 ++ pgs_polygon.sql.in | 18 ++++ sql/path.sql | 6 ++ sql/poly.sql | 7 ++ src/path.c | 29 ++++++ src/path.h | 5 ++ src/point.c | 11 +++ src/point.h | 3 + src/polygon.c | 53 +++++++++++ src/polygon.h | 10 +++ .../pg_sphere--1.2.3--1.3.0.sql.in | 27 ++++++ 16 files changed, 328 insertions(+), 11 deletions(-) diff --git a/doc/functions.sgm b/doc/functions.sgm index 30118bf..5cdc3aa 100644 --- a/doc/functions.sgm +++ b/doc/functions.sgm @@ -463,7 +463,7 @@ Positions at a path - pgSphere provides two functions to + pgSphere provides three functions to get points at a path. @@ -477,6 +477,10 @@ spath path float8 f + + spath_as_array + spath path + The first function returns the i-th @@ -495,6 +499,36 @@ + + + + + + Get i-th point of a path + + + SELECT spoint( spath '{(0, 0),(1, 1)}', 1 );]]> + + + + + + SELECT spoint( spath '{(0, 0),(1, 1)}', 2 );]]> + + + + + + + + + Get array representation of points + + + SELECT spath_as_array( spath '{(0, 0),(1, 1)}');]]> + + + @@ -532,7 +566,58 @@ - + + + Positions at a polygon + + + pgSphere provides two functions to + get points at a path. + + + + spoint + spoly path + int4 i + + + spoly_as_array + spath path + + + + Get by index + + SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 1 );]]> + + + + + + SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 2 );]]> + + + + + + SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 3 );]]> + + + + + + + + Represent points as array + + SELECT spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' );]]> + + + + + + + diff --git a/expected/init_test.out.in b/expected/init_test.out.in index 4b0671c..1276622 100644 --- a/expected/init_test.out.in +++ b/expected/init_test.out.in @@ -24,12 +24,12 @@ psql:pg_sphere.test.sql:158: NOTICE: argument type spath is only a shell psql:pg_sphere.test.sql:177: NOTICE: type "sbox" is not yet defined DETAIL: Creating a shell type definition. psql:pg_sphere.test.sql:184: NOTICE: argument type sbox is only a shell -psql:pg_sphere.test.sql:8568: NOTICE: type "spherekey" is not yet defined +psql:pg_sphere.test.sql:8594: NOTICE: type "spherekey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8575: NOTICE: argument type spherekey is only a shell -psql:pg_sphere.test.sql:8589: NOTICE: type "pointkey" is not yet defined +psql:pg_sphere.test.sql:8601: NOTICE: argument type spherekey is only a shell +psql:pg_sphere.test.sql:8615: NOTICE: type "pointkey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8596: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8602: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8608: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8614: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8622: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8628: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8634: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8640: NOTICE: argument type pointkey is only a shell diff --git a/expected/init_test_healpix.out.in b/expected/init_test_healpix.out.in index 7e725f8..147d4f9 100644 --- a/expected/init_test_healpix.out.in +++ b/expected/init_test_healpix.out.in @@ -1,2 +1,2 @@ -psql:pg_sphere.test.sql:9181: NOTICE: return type smoc is only a shell -psql:pg_sphere.test.sql:9187: NOTICE: argument type smoc is only a shell +psql:pg_sphere.test.sql:9207: NOTICE: return type smoc is only a shell +psql:pg_sphere.test.sql:9213: NOTICE: argument type smoc is only a shell diff --git a/expected/path.out b/expected/path.out index 1734d8c..9f62534 100644 --- a/expected/path.out +++ b/expected/path.out @@ -468,3 +468,28 @@ SELECT spoint(p,2) FROM spheretmp6 WHERE id=2; (1d , -5d) (1 row) +SELECT set_sphere_output( 'RAD' ); + set_sphere_output +------------------- + SET RAD +(1 row) + +-- get n-th point and array representation path points tests +SELECT spoint( spath '{(0, 0),(1, 1)}', 1 ); + spoint +--------- + (0 , 0) +(1 row) + +SELECT spoint( spath '{(0, 0),(1, 1)}', 2 ); + spoint +--------- + (1 , 1) +(1 row) + +SELECT spath_as_array( spath '{(0, 0),(1, 1)}'); + spath_as_array +----------------------- + {"(0 , 0)","(1 , 1)"} +(1 row) + diff --git a/expected/poly.out b/expected/poly.out index a705483..bf7bc0b 100644 --- a/expected/poly.out +++ b/expected/poly.out @@ -1760,3 +1760,33 @@ SELECT npoints( spoly '{ 4 (1 row) +SELECT set_sphere_output( 'RAD' ); + set_sphere_output +------------------- + SET RAD +(1 row) + +SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 1 ); + spoint +--------- + (0 , 0) +(1 row) + +SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 2 ); + spoint +--------- + (1 , 0) +(1 row) + +SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 3 ); + spoint +--------- + (1 , 1) +(1 row) + +SELECT spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' ); + spoly_as_array +--------------------------------- + {"(0 , 0)","(1 , 0)","(1 , 1)"} +(1 row) + diff --git a/pgs_path.sql.in b/pgs_path.sql.in index 94f3222..58268d4 100644 --- a/pgs_path.sql.in +++ b/pgs_path.sql.in @@ -34,6 +34,14 @@ CREATE FUNCTION spoint(spath, float8) COMMENT ON FUNCTION spoint(spath, float8) IS 'returns n-th point of spherical path using linear interpolation'; +CREATE FUNCTION spath_as_array(spath) + RETURNS spoint[] + AS 'MODULE_PATHNAME', 'spherepath_get_array' + LANGUAGE 'c' + IMMUTABLE STRICT PARALLEL SAFE; + +COMMENT ON FUNCTION spath_as_array(spath) IS + 'returns spath as array of points'; -- ****************************** -- diff --git a/pgs_polygon.sql.in b/pgs_polygon.sql.in index df5a614..5db17c6 100644 --- a/pgs_polygon.sql.in +++ b/pgs_polygon.sql.in @@ -11,6 +11,24 @@ CREATE FUNCTION npoints(spoly) COMMENT ON FUNCTION npoints(spoly) IS 'returns number of points of spherical polygon'; +CREATE FUNCTION spoint(spoly, int4) + RETURNS spoint + AS 'MODULE_PATHNAME', 'spherepoly_get_point' + LANGUAGE 'c' + IMMUTABLE STRICT PARALLEL SAFE; + +COMMENT ON FUNCTION spoint(spoly, int4) IS + 'returns n-th point of spherical polygon'; + +CREATE FUNCTION spoly_as_array(spoly) + RETURNS spoint[] + AS 'MODULE_PATHNAME', 'spherepoly_get_array' + LANGUAGE 'c' + IMMUTABLE STRICT PARALLEL SAFE; + +COMMENT ON FUNCTION spoly_as_array(spoly) IS + 'returns spoly as array of points'; + CREATE FUNCTION area(spoly) RETURNS FLOAT8 AS 'MODULE_PATHNAME', 'spherepoly_area' diff --git a/sql/path.sql b/sql/path.sql index fef5c1f..85fb3ff 100644 --- a/sql/path.sql +++ b/sql/path.sql @@ -104,3 +104,9 @@ SELECT set_sphere_output( 'DEG' ); -- test stored data SELECT spoint(p,2) FROM spheretmp6 WHERE id=2; +SELECT set_sphere_output( 'RAD' ); + +-- get n-th point and array representation path points tests +SELECT spoint( spath '{(0, 0),(1, 1)}', 1 ); +SELECT spoint( spath '{(0, 0),(1, 1)}', 2 ); +SELECT spath_as_array( spath '{(0, 0),(1, 1)}'); diff --git a/sql/poly.sql b/sql/poly.sql index 52cedd7..9d7b600 100644 --- a/sql/poly.sql +++ b/sql/poly.sql @@ -603,3 +603,10 @@ SELECT npoints( spoly '{ (1.5121581120647 , -1.93925472462553e-05), (1.51214841579108 , -1.93925472462553e-05) }'); + +SELECT set_sphere_output( 'RAD' ); + +SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 1 ); +SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 2 ); +SELECT spoint( spoly '{(0,0),(1,0),(1,1)}', 3 ); +SELECT spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' ); diff --git a/src/path.c b/src/path.c index b72a753..59a7afc 100644 --- a/src/path.c +++ b/src/path.c @@ -1,4 +1,6 @@ #include "path.h" +#include "point.h" +#include /* * Path functions @@ -50,6 +52,7 @@ PG_FUNCTION_INFO_V1(spheretrans_path); PG_FUNCTION_INFO_V1(spheretrans_path_inverse); PG_FUNCTION_INFO_V1(spherepath_add_point); PG_FUNCTION_INFO_V1(spherepath_add_points_finalize); +PG_FUNCTION_INFO_V1(spherepath_get_array); /* @@ -555,6 +558,32 @@ spherepath_get_point(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } +Datum +spherepath_get_array(PG_FUNCTION_ARGS) +{ + SPATH *path = PG_GETARG_SPATH(0); + Datum *datum_arr = (Datum *) palloc(sizeof(Datum) * path->npts); + ArrayType *res; + SPoint *p = (SPoint *) palloc(sizeof(SPoint) * path->npts); + + for (size_t i = 0; i < path->npts; i++) + { + if (!spath_get_point(&p[i], path, i)) + { + // Clean up and return NULL + for (size_t j = 0; j < i; j++) + pfree(DatumGetPointer(datum_arr[j])); + pfree(datum_arr); + PG_RETURN_NULL(); + } + datum_arr[i] = PointerGetDatum(&p[i]); + } + + res = construct_array(datum_arr, path->npts, get_spoint_type_oid(), sizeof(SPoint), false, 'd'); + + PG_RETURN_ARRAYTYPE_P(res); +} + Datum spherepath_point(PG_FUNCTION_ARGS) { diff --git a/src/path.h b/src/path.h index 1d0fc35..55aa096 100644 --- a/src/path.h +++ b/src/path.h @@ -71,6 +71,11 @@ Datum spherepath_in(PG_FUNCTION_ARGS); */ Datum spherepath_get_point(PG_FUNCTION_ARGS); +/* +* Returns spath as array of points +*/ +Datum spherepath_get_array(PG_FUNCTION_ARGS); + /* * This function interpolates between points of path. Returns the * n-th point of a path where n is a float. diff --git a/src/point.c b/src/point.c index c68ee71..d9d8edc 100644 --- a/src/point.c +++ b/src/point.c @@ -15,6 +15,17 @@ PG_FUNCTION_INFO_V1(spherepoint_z); PG_FUNCTION_INFO_V1(spherepoint_xyz); PG_FUNCTION_INFO_V1(spherepoint_equal); +static Oid point_id = InvalidOid; + +Oid get_spoint_type_oid(void) +{ + if (point_id == InvalidOid) + { + point_id = TypenameGetTypid("spoint"); + } + return point_id; +} + bool spoint_eq(const SPoint *p1, const SPoint *p2) { diff --git a/src/point.h b/src/point.h index 89197d0..87b2862 100644 --- a/src/point.h +++ b/src/point.h @@ -3,6 +3,7 @@ #include "vector3d.h" #include "sbuffer.h" +#include /* This file contains declarations for spherical point and functions. */ @@ -15,6 +16,8 @@ typedef struct float8 lat; /* latitude value in radians */ } SPoint; +Oid get_spoint_type_oid(void); + /* * Calculate the distance between two spherical points in radians. */ diff --git a/src/polygon.c b/src/polygon.c index 17f4841..df3cbb4 100644 --- a/src/polygon.c +++ b/src/polygon.c @@ -11,6 +11,8 @@ PG_FUNCTION_INFO_V1(spherepoly_equal_neg); PG_FUNCTION_INFO_V1(spherepoly_circ); PG_FUNCTION_INFO_V1(spherepoly_npts); PG_FUNCTION_INFO_V1(spherepoly_area); +PG_FUNCTION_INFO_V1(spherepoly_get_point); +PG_FUNCTION_INFO_V1(spherepoly_get_array); PG_FUNCTION_INFO_V1(spherepoly_cont_point); PG_FUNCTION_INFO_V1(spherepoly_cont_point_neg); PG_FUNCTION_INFO_V1(spherepoly_cont_point_com); @@ -556,6 +558,57 @@ spoly_segment(SLine *sl, const SPOLY *poly, int32 i) } } +static bool +poly_get_point(SPoint *sp, const SPOLY *poly, int32 i) +{ + if (i >= 0 && i < poly->npts) + { + memcpy((void *) sp, (void *) &poly->p[i], sizeof(SPoint)); + return true; + } + return false; +} + +Datum +spherepoly_get_point(PG_FUNCTION_ARGS) +{ + int32 i; + SPOLY *poly = PG_GETARG_SPOLY(0); + SPoint *sp = (SPoint *) palloc(sizeof(SPoint)); + + i = PG_GETARG_INT32(1); + if (poly_get_point(sp, poly, i - 1)) + { + PG_RETURN_POINTER(sp); + } + pfree(sp); + PG_RETURN_NULL(); +} + +Datum +spherepoly_get_array(PG_FUNCTION_ARGS) +{ + SPOLY *poly = PG_GETARG_SPOLY(0); + Datum *datum_arr = (Datum *) palloc(sizeof(Datum) * poly->npts); + ArrayType *res; + SPoint *p = (SPoint *) palloc(sizeof(SPoint) * poly->npts); + + for (int i = 0; i < poly->npts; i++) + { + if (!poly_get_point(&p[i], poly, i)) + { + pfree(p); + pfree(datum_arr); + PG_RETURN_NULL(); + } + datum_arr[i] = PointerGetDatum(&p[i]); + } + + res = construct_array(datum_arr, poly->npts, get_spoint_type_oid(), sizeof(SPoint), false, 'd'); + + PG_RETURN_ARRAYTYPE_P(res); +} + /* * Checks whether a polygon contains a point. * diff --git a/src/polygon.h b/src/polygon.h index eefd099..c22e6a2 100644 --- a/src/polygon.h +++ b/src/polygon.h @@ -72,6 +72,11 @@ bool spoly_segment(SLine *sl, const SPOLY *poly, int32 i); */ bool spoly_contains_point(const SPOLY *pg, const SPoint *sp); +/* + * Returns the n-th point of a spoly. + */ +Datum spoly_get_point(PG_FUNCTION_ARGS); + /* * Returns the relationship between a polygon and a line as * PGS_LINE_POLY_REL int8 value. @@ -348,4 +353,9 @@ Datum spherepoly_add_point(PG_FUNCTION_ARGS); */ Datum spherepoly_add_points_finalize(PG_FUNCTION_ARGS); +/* + * Returns spoly as array of points + */ +Datum spherepoly_get_array(PG_FUNCTION_ARGS); + #endif diff --git a/upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in b/upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in index 86cc233..3791852 100644 --- a/upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in +++ b/upgrade_scripts/pg_sphere--1.2.3--1.3.0.sql.in @@ -27,3 +27,30 @@ COMMENT ON FUNCTION spoly_deg(float8[]) IS Two consecutive numbers among those present refer to the same occurrence and cover its latitude and longitude, respectively.'; + +CREATE FUNCTION spath_as_array(spath) + RETURNS spoint[] + AS 'MODULE_PATHNAME', 'spherepath_get_array' + LANGUAGE 'c' + IMMUTABLE STRICT PARALLEL SAFE; + +COMMENT ON FUNCTION spath_as_array(spath) IS + 'returns spath as array of points'; + +CREATE FUNCTION spoint(spoly, int4) + RETURNS spoint + AS 'MODULE_PATHNAME', 'spherepoly_get_point' + LANGUAGE 'c' + IMMUTABLE STRICT PARALLEL SAFE; + +COMMENT ON FUNCTION spoint(spoly, int4) IS + 'returns n-th point of spherical polygon'; + +CREATE FUNCTION spoly_as_array(spoly) + RETURNS spoint[] + AS 'MODULE_PATHNAME', 'spherepoly_get_array' + LANGUAGE 'c' + IMMUTABLE STRICT PARALLEL SAFE; + +COMMENT ON FUNCTION spoly_as_array(spoly) IS + 'returns spoly as array of points';