diff --git a/Makefile b/Makefile
index dca3b7d..63e4e80 100644
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,8 @@ DATA_built = $(RELEASE_SQL) \
DOCS = README.pg_sphere COPYRIGHT.pg_sphere
REGRESS = init tables points euler circle line ellipse poly path box index \
- contains_ops contains_ops_compat bounding_box_gist gnomo epochprop
+ contains_ops contains_ops_compat bounding_box_gist gnomo epochprop \
+ spherepoint_array_center
ifneq ($(USE_HEALPIX),0)
REGRESS += healpix moc mocautocast
diff --git a/doc/functions.sgm b/doc/functions.sgm
index 30118bf..acac332 100644
--- a/doc/functions.sgm
+++ b/doc/functions.sgm
@@ -143,7 +143,7 @@
-
+
strans functions
diff --git a/doc/operators.sgm b/doc/operators.sgm
index 7162a01..18b9873 100644
--- a/doc/operators.sgm
+++ b/doc/operators.sgm
@@ -393,8 +393,10 @@
The center operator @@ is a non-boolean
unary operator returning the center of an object. In the
current implementation of pgSphere,
- only centers of circles and ellipses are supported. Instead
- of using the operator, you can use the function
+ only centers of circles, ellipses, points, arrays of points are
+
+
+ supported. Instead of using the operator, you can use the function
center(object).
@@ -403,6 +405,73 @@
SELECT @@ scircle '<(0d,20d),30d>';]]>
+
+ Center array of points
+
+ SELECT @@ ARRAY[
+ spoint(40.7128, -74.0060),
+ spoint(34.0522, -118.2437),
+ spoint(37.7749, -122.4194)
+] AS center;]]>
+
+
+
+
+
+
+
+
+ Center of a spoint
+
+ For the completeness of the interface, the function returns the point itself
+
+
+ select @@ spoint(0,0) AS spoint;]]>
+
+
+
+
+
+
+
+
+Basic example array of points
+
+ SELECT center(ARRAY[
+ spoint(40.7128, -74.0060),
+ spoint(34.0522, -118.2437),
+ spoint(37.7749, -122.4194)
+]);]]>
+
+
+
+
+
+
+
+
+ Behavior with empty array of points
+
+ SELECT center('{}');]]>
+
+
+
+
+
+
+
+ Example with opposite array points(poles)
+
+ SELECT center(ARRAY[
+ spoint(0, 10),
+ spoint(0, -10),
+]);]]>
+
+
+
+
+
+
diff --git a/expected/init_test.out.in b/expected/init_test.out.in
index 129283c..b81d094 100644
--- a/expected/init_test.out.in
+++ b/expected/init_test.out.in
@@ -24,12 +24,12 @@ psql:pg_sphere.test.sql:159: NOTICE: argument type spath is only a shell
psql:pg_sphere.test.sql:178: NOTICE: type "sbox" is not yet defined
DETAIL: Creating a shell type definition.
psql:pg_sphere.test.sql:185: NOTICE: argument type sbox is only a shell
-psql:pg_sphere.test.sql:8540: NOTICE: type "spherekey" is not yet defined
+psql:pg_sphere.test.sql:8570: NOTICE: type "spherekey" is not yet defined
DETAIL: Creating a shell type definition.
-psql:pg_sphere.test.sql:8547: NOTICE: argument type spherekey is only a shell
-psql:pg_sphere.test.sql:8561: NOTICE: type "pointkey" is not yet defined
+psql:pg_sphere.test.sql:8577: NOTICE: argument type spherekey is only a shell
+psql:pg_sphere.test.sql:8591: NOTICE: type "pointkey" is not yet defined
DETAIL: Creating a shell type definition.
-psql:pg_sphere.test.sql:8568: NOTICE: argument type pointkey is only a shell
-psql:pg_sphere.test.sql:8574: NOTICE: argument type pointkey is only a shell
-psql:pg_sphere.test.sql:8580: NOTICE: argument type pointkey is only a shell
-psql:pg_sphere.test.sql:8586: NOTICE: argument type pointkey is only a shell
+psql:pg_sphere.test.sql:8598: NOTICE: argument type pointkey is only a shell
+psql:pg_sphere.test.sql:8604: NOTICE: argument type pointkey is only a shell
+psql:pg_sphere.test.sql:8610: NOTICE: argument type pointkey is only a shell
+psql:pg_sphere.test.sql:8616: 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 330dc68..26b2c58 100644
--- a/expected/init_test_healpix.out.in
+++ b/expected/init_test_healpix.out.in
@@ -1,2 +1,2 @@
-psql:pg_sphere.test.sql:9153: NOTICE: return type smoc is only a shell
-psql:pg_sphere.test.sql:9159: NOTICE: argument type smoc is only a shell
+psql:pg_sphere.test.sql:9183: NOTICE: return type smoc is only a shell
+psql:pg_sphere.test.sql:9189: NOTICE: argument type smoc is only a shell
diff --git a/expected/points.out b/expected/points.out
index 84375e6..7793c0b 100644
--- a/expected/points.out
+++ b/expected/points.out
@@ -648,3 +648,10 @@ SELECT '( 0h 2m 30s , -90d 0m 0s)'::spoint<->'( 12h 2m 30s , -90d 0m 0s)'::spoin
0
(1 row)
+-- Center operator -------------------
+select @@ spoint(0,0) AS spoint;
+ spoint
+---------
+ (0 , 0)
+(1 row)
+
diff --git a/expected/spherepoint_array_center.out b/expected/spherepoint_array_center.out
new file mode 100644
index 0000000..5fe3273
--- /dev/null
+++ b/expected/spherepoint_array_center.out
@@ -0,0 +1,73 @@
+SELECT center(ARRAY[
+ spoint(40.7128, -74.0060),
+ spoint(34.0522, -118.2437),
+ spoint(37.7749, -122.4194)
+]);
+ center
+----------------------------------------
+ (3.04366980631979 , 0.858938068921891)
+(1 row)
+
+SELECT center('{}'::SPoint[]);
+ center
+--------
+
+(1 row)
+
+CREATE FUNCTION spoint_from_xyz(FLOAT8, FLOAT8, FLOAT8)
+ RETURNS spoint
+ AS 'pg_sphere', 'spoint_from_xyz'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+SELECT spoint_from_xyz(1, 0, 0);
+ spoint_from_xyz
+-----------------
+ (0 , 0)
+(1 row)
+
+SELECT spoint_from_xyz(0, 0, 0);
+ spoint_from_xyz
+-----------------
+ (0 , 0)
+(1 row)
+
+SELECT center(ARRAY[
+ spoint_from_xyz(1, 0, 0),
+ spoint_from_xyz(-1, 0, 0)
+]);
+ center
+-----------------------
+ (1.5707963267949 , 0)
+(1 row)
+
+SELECT center(NULL::SPoint[]);
+ center
+--------
+
+(1 row)
+
+SELECT @@ ARRAY[
+ spoint(40.7128, -74.0060),
+ spoint(34.0522, -118.2437),
+ spoint(37.7749, -122.4194)
+] AS center;
+ center
+----------------------------------------
+ (3.04366980631979 , 0.858938068921891)
+(1 row)
+
+SELECT @@ ARRAY[]::spoint[] AS center;
+ center
+--------
+
+(1 row)
+
+SELECT @@ ARRAY[
+ spoint_from_xyz(1, 0, 0),
+ spoint_from_xyz(-1, 0, 0)
+] AS center;
+ center
+-----------------------
+ (1.5707963267949 , 0)
+(1 row)
+
diff --git a/pgs_point.sql.in b/pgs_point.sql.in
index a9afb84..a1480aa 100644
--- a/pgs_point.sql.in
+++ b/pgs_point.sql.in
@@ -167,3 +167,33 @@ CREATE OPERATOR <-> (
COMMENT ON OPERATOR <-> (spoint, spoint) IS
'distance between spherical points';
+CREATE FUNCTION center(dots_vector SPoint[])
+ RETURNS spoint
+ AS 'MODULE_PATHNAME', 'center'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE OPERATOR @@ (
+ RIGHTARG = SPoint[],
+ PROCEDURE = center
+);
+
+COMMENT ON OPERATOR @@ (NONE , SPoint[]) IS
+ 'Return gravity center from array of spherical points';
+
+CREATE FUNCTION center(spoint)
+ RETURNS spoint
+ AS 'MODULE_PATHNAME', 'spherepoint_center'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+COMMENT ON FUNCTION center(spoint) IS
+ 'For the correctness of the interface, the function returns the spoint itself';
+
+CREATE OPERATOR @@ (
+ RIGHTARG = SPoint,
+ PROCEDURE = center
+);
+
+COMMENT ON OPERATOR @@ (NONE , SPoint) IS
+ 'For the correctness of the interface, the function returns the spoint itself';
diff --git a/sql/points.sql b/sql/points.sql
index a2d53a6..542c240 100644
--- a/sql/points.sql
+++ b/sql/points.sql
@@ -234,3 +234,5 @@ SELECT '( 0h 2m 30s , 90d 0m 0s)'::spoint<->'( 12h 2m 30s , 90d 0m 0s)'::spoint;
SELECT '( 0h 2m 30s , -90d 0m 0s)'::spoint<->'( 12h 2m 30s , -90d 0m 0s)'::spoint;
+-- Center operator -------------------
+select @@ spoint(0,0) AS spoint;
diff --git a/sql/spherepoint_array_center.sql b/sql/spherepoint_array_center.sql
new file mode 100644
index 0000000..9d4d3ff
--- /dev/null
+++ b/sql/spherepoint_array_center.sql
@@ -0,0 +1,37 @@
+SELECT center(ARRAY[
+ spoint(40.7128, -74.0060),
+ spoint(34.0522, -118.2437),
+ spoint(37.7749, -122.4194)
+]);
+
+SELECT center('{}'::SPoint[]);
+
+CREATE FUNCTION spoint_from_xyz(FLOAT8, FLOAT8, FLOAT8)
+ RETURNS spoint
+ AS 'pg_sphere', 'spoint_from_xyz'
+ LANGUAGE 'c'
+ IMMUTABLE STRICT PARALLEL SAFE;
+
+SELECT spoint_from_xyz(1, 0, 0);
+
+SELECT spoint_from_xyz(0, 0, 0);
+
+SELECT center(ARRAY[
+ spoint_from_xyz(1, 0, 0),
+ spoint_from_xyz(-1, 0, 0)
+]);
+
+SELECT center(NULL::SPoint[]);
+
+SELECT @@ ARRAY[
+ spoint(40.7128, -74.0060),
+ spoint(34.0522, -118.2437),
+ spoint(37.7749, -122.4194)
+] AS center;
+
+SELECT @@ ARRAY[]::spoint[] AS center;
+
+SELECT @@ ARRAY[
+ spoint_from_xyz(1, 0, 0),
+ spoint_from_xyz(-1, 0, 0)
+] AS center;
diff --git a/src/point.c b/src/point.c
index 5132835..b997f94 100644
--- a/src/point.c
+++ b/src/point.c
@@ -5,6 +5,7 @@
PG_FUNCTION_INFO_V1(spherepoint_in);
PG_FUNCTION_INFO_V1(spherepoint_from_long_lat);
PG_FUNCTION_INFO_V1(spherepoint_distance);
+PG_FUNCTION_INFO_V1(spherepoint_center);
PG_FUNCTION_INFO_V1(spherepoint_long);
PG_FUNCTION_INFO_V1(spherepoint_lat);
PG_FUNCTION_INFO_V1(spherepoint_x);
@@ -12,6 +13,9 @@ PG_FUNCTION_INFO_V1(spherepoint_y);
PG_FUNCTION_INFO_V1(spherepoint_z);
PG_FUNCTION_INFO_V1(spherepoint_xyz);
PG_FUNCTION_INFO_V1(spherepoint_equal);
+PG_FUNCTION_INFO_V1(spoint_from_xyz);
+PG_FUNCTION_INFO_V1(center);
+
bool
spoint_eq(const SPoint *p1, const SPoint *p2)
@@ -179,6 +183,13 @@ spoint_dist(const SPoint *p1, const SPoint *p2)
}
}
+Datum
+spherepoint_center(PG_FUNCTION_ARGS)
+{
+ SPoint *p = (SPoint *) PG_GETARG_POINTER(0);
+ PG_RETURN_POINTER(p);
+}
+
Datum
spherepoint_distance(PG_FUNCTION_ARGS)
{
@@ -263,3 +274,59 @@ spherepoint_equal(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(spoint_eq(p1, p2));
}
+
+Datum spoint_from_xyz(PG_FUNCTION_ARGS)
+{
+ Vector3D point_coords;
+ SPoint *p = (SPoint *) palloc(sizeof(SPoint));
+
+ point_coords.x = PG_GETARG_FLOAT8(0);
+ point_coords.y = PG_GETARG_FLOAT8(1);
+ point_coords.z = PG_GETARG_FLOAT8(2);
+ vector3d_spoint(p, &point_coords);
+
+ if (p == NULL)
+ {
+ PG_RETURN_NULL();
+ }
+
+ spoint_check(p);
+ PG_RETURN_POINTER(p);
+}
+
+Datum center(PG_FUNCTION_ARGS)
+{
+ int num_elements, i;
+ SPoint * p = (SPoint *) palloc(sizeof(SPoint));
+ SPoint * array_data;
+ Vector3D v;
+ Vector3D point_coords = {0,0,0};
+ ArrayType *dots_vector;
+
+ dots_vector = PG_GETARG_ARRAYTYPE_P(0);
+ num_elements = ArrayGetNItems(ARR_NDIM(dots_vector), ARR_DIMS(dots_vector));
+ if (num_elements <= 0)
+ {
+ PG_RETURN_NULL();
+ }
+
+ array_data = (SPoint *) ARR_DATA_PTR(dots_vector);
+
+ for (i = 0; i < num_elements; i++)
+ {
+ spoint_vector3d(&v, &array_data[i]);
+ point_coords.x += v.x;
+ point_coords.y += v.y;
+ point_coords.z += v.z;
+ }
+
+ point_coords.x /= num_elements;
+ point_coords.y /= num_elements;
+ point_coords.z /= num_elements;
+
+ vector3d_spoint(p, &point_coords);
+
+ spoint_check(p);
+
+ PG_RETURN_POINTER(p);
+}
diff --git a/src/point.h b/src/point.h
index 76c2202..9c4984c 100644
--- a/src/point.h
+++ b/src/point.h
@@ -15,6 +15,11 @@ typedef struct
float8 lat; /* latitude value in radians */
} SPoint;
+/*
+ * For the correctness of the interface, the function returns the spoint itself
+ */
+Datum spherepoint_center(PG_FUNCTION_ARGS);
+
/*
* Calculate the distance between two spherical points in radians.
*/
@@ -90,4 +95,9 @@ Datum spherepoint_xyz(PG_FUNCTION_ARGS);
*/
Datum spherepoint_equal(PG_FUNCTION_ARGS);
+/*
+ * Return gravity center from array of spherical points
+ */
+Datum center(PG_FUNCTION_ARGS);
+
#endif