From d8470f8972864e556010b0fe3ed448c6a884db29 Mon Sep 17 00:00:00 2001 From: ggnmstr Date: Thu, 27 Jul 2023 16:58:33 +0700 Subject: [PATCH] Add spoly_is_convex --- doc/functions.sgm | 27 ++++++++++ expected/init_test.out.in | 14 ++--- expected/init_test_healpix.out.in | 4 +- expected/poly.out | 25 +++++++++ pgs_polygon.sql.in | 14 +++++ sql/poly.sql | 6 +++ src/polygon.c | 52 +++++++++++++++++++ src/polygon.h | 5 ++ .../pg_sphere--1.2.3--1.3.0.sql.in | 9 ++++ 9 files changed, 147 insertions(+), 9 deletions(-) diff --git a/doc/functions.sgm b/doc/functions.sgm index 5cdc3aa..d5bb457 100644 --- a/doc/functions.sgm +++ b/doc/functions.sgm @@ -618,6 +618,33 @@ + + + + Spoly is convex + + + Returns true if the specified spherical polygon is convex. + Returns false otherwise. + + + + spoly_is_convex + spoly polygon + + + + Check if polygon is convex + + SELECT spoly_is_convex( spoly '{(0,0),(1,0),(1,1),(1,2)}' );]]> + + + + + + + + diff --git a/expected/init_test.out.in b/expected/init_test.out.in index b5ace10..6fbd06b 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:8644: NOTICE: type "spherekey" is not yet defined +psql:pg_sphere.test.sql:8658: NOTICE: type "spherekey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8651: NOTICE: argument type spherekey is only a shell -psql:pg_sphere.test.sql:8665: NOTICE: type "pointkey" is not yet defined +psql:pg_sphere.test.sql:8665: NOTICE: argument type spherekey is only a shell +psql:pg_sphere.test.sql:8679: NOTICE: type "pointkey" is not yet defined DETAIL: Creating a shell type definition. -psql:pg_sphere.test.sql:8672: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8678: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8684: NOTICE: argument type pointkey is only a shell -psql:pg_sphere.test.sql:8690: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8686: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8692: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8698: NOTICE: argument type pointkey is only a shell +psql:pg_sphere.test.sql:8704: 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 3b0cfbd..4195603 100644 --- a/expected/init_test_healpix.out.in +++ b/expected/init_test_healpix.out.in @@ -1,2 +1,2 @@ -psql:pg_sphere.test.sql:9257: NOTICE: return type smoc is only a shell -psql:pg_sphere.test.sql:9263: NOTICE: argument type smoc is only a shell +psql:pg_sphere.test.sql:9271: NOTICE: return type smoc is only a shell +psql:pg_sphere.test.sql:9277: NOTICE: argument type smoc is only a shell diff --git a/expected/poly.out b/expected/poly.out index 9fcd234..50e510e 100644 --- a/expected/poly.out +++ b/expected/poly.out @@ -1799,3 +1799,28 @@ SELECT spoly_as_array( spoly '{(0,0),(1,0),(1,1)}' ); {"(0 , 0)","(1 , 0)","(1 , 1)"} (1 row) +-- spoly is convex +SELECT spoly_is_convex(spoly'{(53d 45m 35.0s, 37d 6m 30.0s), (52d 21m 36.0s, 41d 36m 7.0s), (54d 14m 18.0s, 45d 1m 35.0s), (51d 23m 3.0s, 45d 22m 49.0s), (51d 2m 12.0s, 41d 52m 1.0s), (50d 41m 47.0s, 38d 22m 0s) }'); + spoly_is_convex +----------------- + f +(1 row) + +SELECT spoly_is_convex(spoly'{(12d,32d),(34d,12d),(59d,21d),(69d,21d)}'); + spoly_is_convex +----------------- + f +(1 row) + +SELECT spoly_is_convex(spoly'{(12d,32d),(34d,12d),(59d,21d),(34d,40d)}'); + spoly_is_convex +----------------- + t +(1 row) + +SELECT spoly_is_convex(NULL); + spoly_is_convex +----------------- + f +(1 row) + diff --git a/pgs_polygon.sql.in b/pgs_polygon.sql.in index 5db17c6..fdd4277 100644 --- a/pgs_polygon.sql.in +++ b/pgs_polygon.sql.in @@ -973,3 +973,17 @@ CREATE AGGREGATE spoly ( stype = spoly, finalfunc = spoly_add_points_fin_aggr ); + + +-- +-- polygon is convex +-- + +CREATE FUNCTION spoly_is_convex(spoly) + RETURNS BOOL + AS 'MODULE_PATHNAME', 'spherepoly_is_convex' + LANGUAGE 'c' + IMMUTABLE PARALLEL SAFE; + +COMMENT ON FUNCTION spoly_is_convex(spoly) IS + 'true if spherical polygon is convex'; diff --git a/sql/poly.sql b/sql/poly.sql index b185e50..2281aba 100644 --- a/sql/poly.sql +++ b/sql/poly.sql @@ -616,3 +616,9 @@ 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)}' ); + +-- spoly is convex +SELECT spoly_is_convex(spoly'{(53d 45m 35.0s, 37d 6m 30.0s), (52d 21m 36.0s, 41d 36m 7.0s), (54d 14m 18.0s, 45d 1m 35.0s), (51d 23m 3.0s, 45d 22m 49.0s), (51d 2m 12.0s, 41d 52m 1.0s), (50d 41m 47.0s, 38d 22m 0s) }'); +SELECT spoly_is_convex(spoly'{(12d,32d),(34d,12d),(59d,21d),(69d,21d)}'); +SELECT spoly_is_convex(spoly'{(12d,32d),(34d,12d),(59d,21d),(34d,40d)}'); +SELECT spoly_is_convex(NULL); diff --git a/src/polygon.c b/src/polygon.c index 54eb2a6..57786b8 100644 --- a/src/polygon.c +++ b/src/polygon.c @@ -59,6 +59,7 @@ PG_FUNCTION_INFO_V1(spheretrans_poly); PG_FUNCTION_INFO_V1(spheretrans_poly_inverse); PG_FUNCTION_INFO_V1(spherepoly_add_point); PG_FUNCTION_INFO_V1(spherepoly_add_points_finalize); +PG_FUNCTION_INFO_V1(spherepoly_is_convex); /* @@ -1531,3 +1532,54 @@ spherepoly_add_points_finalize(PG_FUNCTION_ARGS) } PG_RETURN_POINTER(poly); } + + +Datum +spherepoly_is_convex(PG_FUNCTION_ARGS) +{ + Vector3D u, + v, + vsu, + wsv, + crs; + int32 i; + float8 cur = 0.0, + prev = 0.0; + SPOLY *poly = (SPOLY *) PG_GETARG_POINTER(0); + + if (poly == NULL) + { + PG_RETURN_BOOL(false); + } + + poly = PG_GETARG_SPOLY(0); + if (poly->npts == 3) + { + PG_RETURN_BOOL(true); + } + + for (i = 0; i < poly->npts; i++) + { + const int j = (i - 1 + poly->npts) % poly->npts; + const int k = (i + 1) % poly->npts; + + spoint_vector3d(&u, &poly->p[i]); + spoint_vector3d(&v, &poly->p[j]); + spoint_vector3d(&vsu, &poly->p[j]); + spoint_vector3d(&wsv, &poly->p[k]); + + vector3d_addwithscalar(&vsu, -1, &u); + vector3d_addwithscalar(&wsv, -1, &v); + + vector3d_cross(&crs, &vsu, &wsv); + + cur = vector3d_scalar(&crs, &v); + if (cur * prev < 0) + { + PG_RETURN_BOOL(false); + } + prev = cur; + } + + PG_RETURN_BOOL(true); +} diff --git a/src/polygon.h b/src/polygon.h index c7daf13..9d47f40 100644 --- a/src/polygon.h +++ b/src/polygon.h @@ -358,4 +358,9 @@ Datum spherepoly_add_points_finalize(PG_FUNCTION_ARGS); */ Datum spherepoly_get_array(PG_FUNCTION_ARGS); +/* + * Checks whether a polygon is convex + */ +Datum spherepoly_is_convex(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 6eb9460..6309349 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 @@ -93,3 +93,12 @@ CREATE OPERATOR <-> ( COMMENT ON OPERATOR <-> (spoint, sline) IS 'returns the distance between spherical line and spherical point'; + +CREATE FUNCTION spoly_is_convex(spoly) + RETURNS BOOL + AS 'MODULE_PATHNAME', 'spherepoly_is_convex' + LANGUAGE 'c' + IMMUTABLE PARALLEL SAFE; + +COMMENT ON FUNCTION spoly_is_convex(spoly) IS + 'true if spherical polygon is convex';