From 2f9fe2c10402a4676e7855851c66d970eba7321f Mon Sep 17 00:00:00 2001 From: Darya177777 Date: Fri, 11 Aug 2023 09:29:42 +0700 Subject: [PATCH] Add calculation of the distance between a line and a point --- doc/operators.sgm | 14 +++- expected/init_test.out.in | 14 ++-- expected/init_test_healpix.out.in | 4 +- expected/line.out | 34 ++++++++- pgs_line.sql.in | 50 +++++++++++++ sql/line.sql | 17 ++++- src/line.c | 72 +++++++++++++++++++ src/line.h | 15 ++++ .../pg_sphere--1.2.3--1.3.0.sql.in | 39 ++++++++++ 9 files changed, 247 insertions(+), 12 deletions(-) diff --git a/doc/operators.sgm b/doc/operators.sgm index 7162a01..73ebb83 100644 --- a/doc/operators.sgm +++ b/doc/operators.sgm @@ -331,7 +331,8 @@ a non-boolean operator returning the distance between two objects in radians. Currently, pgSphere supports only distances - between points, circles, and between point and circle. If the + between points, circles, between point and circle, and + between point and line. If the objects are overlapping, the distance operator returns zero (0.0). @@ -343,6 +344,17 @@ + + + + + Distance between point and line + + SELECT 180 * (sline '( 0d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )')]]> + + + + diff --git a/expected/init_test.out.in b/expected/init_test.out.in index 1276622..b5ace10 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:8594: NOTICE: type "spherekey" is not yet defined +psql:pg_sphere.test.sql:8644: NOTICE: type "spherekey" is not yet defined DETAIL: Creating a shell type definition. -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 +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 DETAIL: Creating a shell type definition. -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 +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 diff --git a/expected/init_test_healpix.out.in b/expected/init_test_healpix.out.in index 147d4f9..3b0cfbd 100644 --- a/expected/init_test_healpix.out.in +++ b/expected/init_test_healpix.out.in @@ -1,2 +1,2 @@ -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 +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 diff --git a/expected/line.out b/expected/line.out index b05286b..eb4d2ac 100644 --- a/expected/line.out +++ b/expected/line.out @@ -4,6 +4,7 @@ SET 8 (1 row) +SET extra_float_digits TO -3; -- checking spherical line operators SELECT sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) = sline ( spoint '(0, 90d)', spoint '(0, -89d)' ) ; @@ -134,4 +135,35 @@ SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # f (1 row) - +-- checking the distance between a line and a point +SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )'; + ?column? +---------------- + 0.872664625997 +(1 row) + +SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )' = + spoint '( 0d, 90d )' <-> sline '( 90d, 0d, 0d, XYZ ), 40d '; + ?column? +---------- + t +(1 row) + +SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 90d )'; + ?column? +--------------- + 1.57079632679 +(1 row) + +SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 0d )'; + ?column? +---------- + 0 +(1 row) + +SELECT sline '( 0d, 0d, 0d, XYZ ), 30d ' <-> spoint '( 0d, 30d )'; + ?column? +---------------- + 0.523598775598 +(1 row) + diff --git a/pgs_line.sql.in b/pgs_line.sql.in index 9814355..3b51fba 100644 --- a/pgs_line.sql.in +++ b/pgs_line.sql.in @@ -593,3 +593,53 @@ COMMENT ON FUNCTION scircle_contains_line_com_neg(sline, scircle) IS 'returns true if spherical circle does not contain spherical line'; +-- +-- distance between line and point +-- + +CREATE FUNCTION dist(sline, spoint) + RETURNS FLOAT8 + AS 'MODULE_PATHNAME', 'sphereline_point_distance' + LANGUAGE 'c' + IMMUTABLE STRICT; + +COMMENT ON FUNCTION dist(sline, spoint) IS + 'returns the distance between spherical line and spherical point'; + + +CREATE OPERATOR <-> ( + LEFTARG = sline, + RIGHTARG = spoint, + COMMUTATOR = '<->', + PROCEDURE = dist +); + +COMMENT ON OPERATOR <-> (sline, spoint) IS + 'returns the distance between spherical line and spherical point'; + + + +-- +-- distance between point and line +-- + +CREATE FUNCTION dist(spoint, sline) + RETURNS FLOAT8 + AS 'MODULE_PATHNAME', 'sphereline_point_distance_com' + LANGUAGE 'c' + IMMUTABLE STRICT; + +COMMENT ON FUNCTION dist(spoint, sline) IS + 'returns the distance between spherical line and spherical point'; + + +CREATE OPERATOR <-> ( + LEFTARG = spoint, + RIGHTARG = sline, + COMMUTATOR = '<->', + PROCEDURE = dist +); + +COMMENT ON OPERATOR <-> (spoint, sline) IS + 'returns the distance between spherical line and spherical point'; + diff --git a/sql/line.sql b/sql/line.sql index 7fc6ebf..7a5a2dd 100644 --- a/sql/line.sql +++ b/sql/line.sql @@ -1,6 +1,7 @@ \set ECHO none SELECT set_sphere_output_precision(8); \set ECHO all +SET extra_float_digits TO -3; -- checking spherical line operators @@ -66,4 +67,18 @@ SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # SELECT sline ( spoint '(0, 0d)', spoint '(0.000001d, 0d)' ) # sline ( spoint '(0.000001d, 0d)', spoint '(0.000001d, 0.0000005d)' ) ; - \ No newline at end of file + + +-- checking the distance between a line and a point + + +SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )'; + +SELECT sline '( 90d, 0d, 0d, XYZ ), 40d ' <-> spoint '( 0d, 90d )' = + spoint '( 0d, 90d )' <-> sline '( 90d, 0d, 0d, XYZ ), 40d '; + +SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 90d )'; + +SELECT sline '( 0d, 0d, 0d, XYZ ), 0d ' <-> spoint '( 0d, 0d )'; + +SELECT sline '( 0d, 0d, 0d, XYZ ), 30d ' <-> spoint '( 0d, 30d )'; diff --git a/src/line.c b/src/line.c index b8d1195..6599e64 100644 --- a/src/line.c +++ b/src/line.c @@ -33,6 +33,8 @@ PG_FUNCTION_INFO_V1(sphereline_overlap_neg); PG_FUNCTION_INFO_V1(spheretrans_from_line); PG_FUNCTION_INFO_V1(spheretrans_line); PG_FUNCTION_INFO_V1(spheretrans_line_inverse); +PG_FUNCTION_INFO_V1(sphereline_point_distance); +PG_FUNCTION_INFO_V1(sphereline_point_distance_com); /* * Swaps the beginning and ending of the line. @@ -642,6 +644,59 @@ sline_center(SPoint *c, const SLine *sl) euler_spoint_trans(c, &p, &se); } +float8 sline_point_dist(const SLine *sl, const SPoint *p) +{ + Vector3D v_beg; + Vector3D v_end; + Vector3D v; + Vector3D normal1; + Vector3D normal2; + Vector3D line; + Vector3D first_p; + float8 norma; + SPoint fp; + SPoint sp; + float8 fpdist; + float8 spdist; + + if (spoint_at_sline(p, sl)) + { + return 0.0; + } + + sline_vector_begin(&v_beg, sl); + sline_vector_end(&v_end, sl); + spoint_vector3d(&v, p); + + /* normal1 to the plane passing through the line and the center of the sphere */ + vector3d_cross(&normal1, &v_beg, &v_end); + if (vector3d_eq(&normal1, &v)) + { + return PIH; + } + + /* normal2 to the plane perpendicular to the given line. */ + vector3d_cross(&normal2, &normal1, &v); + vector3d_cross(&line, &normal2, &normal1); + norma = sqrt(line.x * line.x + line.y * line.y + line.z * line.z); + + first_p.x = line.x / norma; + first_p.y = line.y / norma; + first_p.z = line.z / norma; + vector3d_spoint(&fp, &first_p); + + if (spoint_at_sline(&fp, sl)) + { + return spoint_dist(&fp, p); + } + + vector3d_spoint(&fp, &v_beg); + vector3d_spoint(&sp, &v_end); + fpdist = spoint_dist(p, &fp); + spdist = spoint_dist(p, &sp); + return Min(fpdist, spdist); +} + Datum sphereline_in(PG_FUNCTION_ARGS) { @@ -1051,3 +1106,20 @@ spheretrans_from_line(PG_FUNCTION_ARGS) sphereline_to_euler(e, l); PG_RETURN_POINTER(e); } + +Datum +sphereline_point_distance(PG_FUNCTION_ARGS) +{ + const SLine *s = (SLine *) PG_GETARG_POINTER(0); + const SPoint *p = (SPoint *) PG_GETARG_POINTER(1); + PG_RETURN_FLOAT8(sline_point_dist(s, p)); +} + +Datum +sphereline_point_distance_com(PG_FUNCTION_ARGS) +{ + const SPoint *p = (SPoint *) PG_GETARG_POINTER(0); + const SLine *s = (SLine *) PG_GETARG_POINTER(1); + PG_RETURN_FLOAT8(sline_point_dist(s, p)); +} + diff --git a/src/line.h b/src/line.h index 1a41767..002f371 100644 --- a/src/line.h +++ b/src/line.h @@ -129,6 +129,11 @@ void euler_sline_trans(SLine *out, const SLine *in, const SEuler *se); */ void sline_center(SPoint *c, const SLine *sl); +/* + * Calculates the distance between a line 'sl' and a point 'p' + */ +float8 sline_point_dist(const SLine *sl, const SPoint *p); + /* * The input function for spherical line. */ @@ -290,4 +295,14 @@ Datum spheretrans_line(PG_FUNCTION_ARGS); */ Datum spheretrans_line_inverse(PG_FUNCTION_ARGS); +/* + * Returns the distance between a line and a point. + */ +Datum sphereline_point_distance(PG_FUNCTION_ARGS); + +/* + * Returns the distance between a point and a line. + */ +Datum sphereline_point_distance_com(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 3791852..6eb9460 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 @@ -54,3 +54,42 @@ CREATE FUNCTION spoly_as_array(spoly) COMMENT ON FUNCTION spoly_as_array(spoly) IS 'returns spoly as array of points'; + +CREATE FUNCTION dist(sline, spoint) + RETURNS FLOAT8 + AS 'MODULE_PATHNAME', 'sphereline_point_distance' + LANGUAGE 'c' + IMMUTABLE STRICT; + +COMMENT ON FUNCTION dist(sline, spoint) IS + 'returns the distance between spherical line and spherical point'; + +CREATE OPERATOR <-> ( + LEFTARG = sline, + RIGHTARG = spoint, + COMMUTATOR = '<->', + PROCEDURE = dist +); + +COMMENT ON OPERATOR <-> (sline, spoint) IS + 'returns the distance between spherical line and spherical point'; + +CREATE FUNCTION dist(spoint, sline) + RETURNS FLOAT8 + AS 'MODULE_PATHNAME', 'sphereline_point_distance_com' + LANGUAGE 'c' + IMMUTABLE STRICT; + +COMMENT ON FUNCTION dist(spoint, sline) IS + 'returns the distance between spherical line and spherical point'; + + +CREATE OPERATOR <-> ( + LEFTARG = spoint, + RIGHTARG = sline, + COMMUTATOR = '<->', + PROCEDURE = dist +); + +COMMENT ON OPERATOR <-> (spoint, sline) IS + 'returns the distance between spherical line and spherical point';