This is an automated email from the ASF dual-hosted git repository.

imaxon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git

commit 72a01fe09f0913eb8f7850a09458086586c41bf9
Author: sshiv012 <[email protected]>
AuthorDate: Tue Feb 17 12:43:32 2026 -0800

    [ASTERIXDB-3705][GEO] Add new geospatial functions
    
     - user model changes: no
    - storage format changes: no
    - interface changes: no
    
    Details:
      - Add new geospatial functions: st_convex_hull, st_centroid,
        st_is_valid, st_reverse, st_flip_coordinates,
        st_distance_sphere (haversine), st_dwithin, and st_buffer
      - Register all new functions in BuiltinFunctions and GeoFunctionRegistrant
      - Add SQL++ integration tests and expected results for all new functions
      - Updates docs
      Bug fix:
      - Fix st_point_n (AbstractSTGeometryNDescriptor) returning stale results
        by adding missing resultStorage.reset() call before each evaluation
    
    Change-Id: Ic4791ce4934ff3a1dd9051ddb13846a4bea4e5c1
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/20904
    Integration-Tests: Jenkins <[email protected]>
    Tested-by: Jenkins <[email protected]>
    Reviewed-by: Ian Maxon <[email protected]>
---
 .../single-method/single-method.16.query.sqlpp     |  24 ++++
 .../single-method/single-method.17.query.sqlpp     |  22 ++++
 .../single-method/single-method.18.query.sqlpp     |  22 ++++
 .../single-method/single-method.19.query.sqlpp     |  23 ++++
 .../single-method/single-method.20.query.sqlpp     |  24 ++++
 .../single-method/single-method.21.query.sqlpp     |  22 ++++
 .../two-geometries/two-geometries.06.query.sqlpp   |  25 ++++
 .../results/geojson/datatype/result.08.adm         |   4 +-
 .../results/geojson/single-method/result.16.adm    |   1 +
 .../results/geojson/single-method/result.17.adm    |   1 +
 .../results/geojson/single-method/result.18.adm    |   1 +
 .../results/geojson/single-method/result.19.adm    |   1 +
 .../results/geojson/single-method/result.20.adm    |   1 +
 .../results/geojson/single-method/result.21.adm    |   1 +
 .../results/geojson/two-geometries/result.06.adm   |  10 ++
 .../asterix-doc/src/site/markdown/geo/functions.md | 102 +++++++++++++++
 .../geo/evaluators/GeoFunctionRegistrant.java      |  16 +++
 .../functions/AbstractSTGeometryNDescriptor.java   |   1 +
 ...tryNDescriptor.java => STBufferDescriptor.java} |  77 ++++++------
 .../evaluators/functions/STCentroidDescriptor.java |  42 +++++++
 .../functions/STConvexHullDescriptor.java          |  42 +++++++
 .../evaluators/functions/STDWithinDescriptor.java  | 139 +++++++++++++++++++++
 .../functions/STDistanceSphereDescriptor.java      |  59 +++++++++
 .../functions/STFlipCoordinatesDescriptor.java     |  69 ++++++++++
 .../evaluators/functions/STIsValidDescriptor.java  |  42 +++++++
 .../evaluators/functions/STReverseDescriptor.java  |  42 +++++++
 .../asterix/om/functions/BuiltinFunctions.java     |  19 +++
 27 files changed, 793 insertions(+), 39 deletions(-)

diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.16.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.16.query.sqlpp
new file mode 100644
index 0000000000..85e39a3948
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.16.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+{
+"a": st_as_text(st_convex_hull(st_geom_from_text("MULTIPOINT(0 0, 1 0, 1 1, 0 
1, 0.5 0.5)"))),
+"b": st_as_text(st_centroid(st_geom_from_text("POLYGON((0 0, 10 0, 10 10, 0 
10, 0 0))"))),
+"c": st_is_valid(st_geom_from_text("POLYGON((0 0, 1 1, 1 0, 0 1, 0 0))")),
+"d": st_is_valid(st_geom_from_text("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))"))
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.17.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.17.query.sqlpp
new file mode 100644
index 0000000000..97d34b302e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.17.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+{
+"a": st_as_text(st_reverse(st_geom_from_text("LINESTRING(0 0, 1 1, 2 2)"))),
+"b": st_as_text(st_reverse(st_geom_from_text("POLYGON((0 0, 1 0, 1 1, 0 1, 0 
0))")))
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.18.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.18.query.sqlpp
new file mode 100644
index 0000000000..bfeaf82142
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.18.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+{
+"a": st_as_text(st_flip_coordinates(st_geom_from_text("POINT(1 2)"))),
+"b": st_as_text(st_flip_coordinates(st_geom_from_text("LINESTRING(1 2, 3 4)")))
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.19.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.19.query.sqlpp
new file mode 100644
index 0000000000..41036d44d7
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.19.query.sqlpp
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+{
+"a": st_as_text(st_buffer(st_geom_from_text("POINT(0 0)"), 0.0)),
+"b": st_area(st_buffer(st_geom_from_text("POINT(0 0)"), 1.0)) > 3.0,
+"c": st_area(st_buffer(st_geom_from_text("POINT(0 0)"), 1.0)) > 4.0
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.20.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.20.query.sqlpp
new file mode 100644
index 0000000000..972e66b7ce
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.20.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+{
+"a": st_distance_sphere(st_geom_from_text("POINT(0 0)"), 
st_geom_from_text("POINT(0 0)")),
+"b": st_distance_sphere(st_geom_from_text("POINT(0 0)"), 
st_geom_from_text("POINT(1 0)")),
+"c": st_distance_sphere(st_geom_from_text("POINT(0 0)"), 
st_geom_from_text("POINT(0 1)")),
+"d": st_distance_sphere(st_geom_from_text("POINT(0 0)"), 
st_geom_from_text("POINT(0.001 0)"))
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.21.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.21.query.sqlpp
new file mode 100644
index 0000000000..27d1625771
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/single-method/single-method.21.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+{
+"a": st_dwithin(st_geom_from_text("POINT(0 0)"), st_geom_from_text("POINT(1 
0)"), 2.0),
+"b": st_dwithin(st_geom_from_text("POINT(0 0)"), st_geom_from_text("POINT(5 
0)"), 2.0)
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/two-geometries/two-geometries.06.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/two-geometries/two-geometries.06.query.sqlpp
new file mode 100644
index 0000000000..6233489a8b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/geojson/two-geometries/two-geometries.06.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+use GeoJSON1;
+
+SELECT VALUE {
+  "DWithin_0_5": st_dwithin(geo.myGeometry1, geo.myGeometry2, 0.5),
+  "DWithin5": st_dwithin(geo.myGeometry1, geo.myGeometry2, 5.0)
+}
+FROM Geometries geo ORDER BY geo.id;
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm
index 198797093f..cbadf0bb89 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm
@@ -1,3 +1,3 @@
 { "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842]}, 
"StartPoint": {"type":"Point","coordinates":[-69.1991349,-12.6006222]}, 
"Envelope": 
{"type":"Polygon","coordinates":[[[-69.199136,-12.6010968],[-69.199136,-12.5998133],[-69.1972972,-12.5998133],[-69.1972972,-12.6010968],[-69.199136,-12.6010968]]]}
 }
-{ "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842]}, 
"StartPoint": {"type":"Point","coordinates":[-113.98,39.198]}, "Envelope": 
{"type":"Polygon","coordinates":[[[-113.981,39.195],[-113.981,39.198],[-113.98,39.198],[-113.98,39.195],[-113.981,39.195]]]}
 }
-{ "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842]}, 
"StartPoint": {"type":"Point","coordinates":[1,2]}, "Envelope": 
{"type":"Polygon","coordinates":[[[1,2],[1,8],[7,8],[7,2],[1,2]]]} }
\ No newline at end of file
+{ "PointN": {"type":"Point","coordinates":[-113.981,39.195]}, "StartPoint": 
{"type":"Point","coordinates":[-113.98,39.198]}, "Envelope": 
{"type":"Polygon","coordinates":[[[-113.981,39.195],[-113.981,39.198],[-113.98,39.198],[-113.98,39.195],[-113.981,39.195]]]}
 }
+{ "PointN": {"type":"Point","coordinates":[4,5]}, "StartPoint": 
{"type":"Point","coordinates":[1,2]}, "Envelope": 
{"type":"Polygon","coordinates":[[[1,2],[1,8],[7,8],[7,2],[1,2]]]} }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.16.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.16.adm
new file mode 100644
index 0000000000..606c5c613f
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.16.adm
@@ -0,0 +1 @@
+{ "a": "POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))", "b": "POINT (5 5)", "c": false, 
"d": true }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.17.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.17.adm
new file mode 100644
index 0000000000..ee0219f578
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.17.adm
@@ -0,0 +1 @@
+{ "a": "LINESTRING (2 2, 1 1, 0 0)", "b": "POLYGON ((0 0, 0 1, 1 1, 1 0, 0 
0))" }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.18.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.18.adm
new file mode 100644
index 0000000000..e73d9f3352
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.18.adm
@@ -0,0 +1 @@
+{ "a": "POINT (2 1)", "b": "LINESTRING (2 1, 4 3)" }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.19.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.19.adm
new file mode 100644
index 0000000000..e35cdf0b80
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.19.adm
@@ -0,0 +1 @@
+{ "a": "POLYGON EMPTY", "b": true, "c": false }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.20.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.20.adm
new file mode 100644
index 0000000000..a591562fbe
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.20.adm
@@ -0,0 +1 @@
+{ "a": 0.0, "b": 111195.0662708989, "c": 111195.0662708989, "d": 
111.1950662708989 }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.21.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.21.adm
new file mode 100644
index 0000000000..7846424f35
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.21.adm
@@ -0,0 +1 @@
+{ "a": true, "b": false }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.06.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.06.adm
new file mode 100644
index 0000000000..9ed21094e6
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.06.adm
@@ -0,0 +1,10 @@
+{ "DWithin_0_5": true, "DWithin5": true }
+{ "DWithin_0_5": true, "DWithin5": true }
+{ "DWithin_0_5": true, "DWithin5": true }
+{ "DWithin_0_5": true, "DWithin5": true }
+{ "DWithin_0_5": true, "DWithin5": true }
+{ "DWithin_0_5": false, "DWithin5": true }
+{ "DWithin_0_5": true, "DWithin5": true }
+{ "DWithin_0_5": false, "DWithin5": true }
+{ "DWithin_0_5": true, "DWithin5": true }
+{ "DWithin_0_5": true, "DWithin5": true }
diff --git a/asterixdb/asterix-doc/src/site/markdown/geo/functions.md 
b/asterixdb/asterix-doc/src/site/markdown/geo/functions.md
index 2bd22507f4..e91568f4d4 100644
--- a/asterixdb/asterix-doc/src/site/markdown/geo/functions.md
+++ b/asterixdb/asterix-doc/src/site/markdown/geo/functions.md
@@ -333,6 +333,17 @@ There are primitive functions that take as input 
geometry/es and return a primit
   
         0.30901547439030225
 
+### st_distance_sphere ###
+* Return the minimum distance in meters between two point geometries using 
spherical (haversine) calculation.
+
+* Example:
+  * Command:
+
+        st_distance_sphere(st_geom_from_text('POINT(0 0)'), 
st_geom_from_text('POINT(1 0)'));
+  * Result:
+
+        111195.0662708989
+
 ## <a id="predicate">Spatial Predicate</a>
 Spatial predicate functions test for a relationship between two geometries and 
return a Boolean value (true/false).
 
@@ -482,6 +493,42 @@ Spatial predicate functions test for a relationship 
between two geometries and r
 ### st_within ###
 * Return true if the geometry A is completely inside geometry B.
 
+### st_is_valid ###
+* Return TRUE if the geometry is topologically valid.
+
+* Example:
+  * Command:
+
+        st_is_valid(st_geom_from_text("POLYGON((0 0, 1 1, 1 0, 0 1, 0 0))"));
+  * Result:
+
+        false
+* Example:
+  * Command:
+
+        st_is_valid(st_geom_from_text("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))"));
+  * Result:
+
+        true
+
+### st_dwithin ###
+* Return TRUE if the two geometries are within the specified distance of one 
another.
+
+* Example:
+  * Command:
+
+        st_dwithin(st_geom_from_text('POINT(0 0)'), st_geom_from_text('POINT(1 
0)'), 2.0);
+  * Result:
+
+        true
+* Example:
+  * Command:
+
+        st_dwithin(st_geom_from_text('POINT(0 0)'), st_geom_from_text('POINT(5 
0)'), 2.0);
+  * Result:
+
+        false
+
 ## <a id="analysis">Spatial Analysis</a>
 Spatial analysis functions take as input one or more geometries and return a 
geometry as output.
 
@@ -617,6 +664,61 @@ Spatial analysis functions take as input one or more 
geometries and return a geo
   
         
{"type":"MultiLineString","coordinates":[[[0,2],[1,2],[2,2],[1,1]],[[5,2],[4,2],[3,3],[4,4],[5,5],[6,6]]],"crs":null}
 
+### st_convex_hull ###
+* Return a geometry that represents the convex hull of the input geometry.
+
+* Example:
+  * Command:
+
+        st_convex_hull(st_geom_from_text('MULTIPOINT(0 0, 1 0, 1 1, 0 1, 0.5 
0.5)'));
+  * Result:
+
+        {"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]]]}
+
+### st_centroid ###
+* Return a point geometry representing the geometric center of the input 
geometry.
+
+* Example:
+  * Command:
+
+        st_centroid(st_geom_from_text('POLYGON((0 0, 10 0, 10 10, 0 10, 0 
0))'));
+  * Result:
+
+        {"type":"Point","coordinates":[5,5]}
+
+### st_reverse ###
+* Return the geometry with vertex order reversed.
+
+* Example:
+  * Command:
+
+        st_reverse(st_geom_from_text('LINESTRING(0 0, 1 1, 2 2)'));
+  * Result:
+
+        {"type":"LineString","coordinates":[[2,2],[1,1],[0,0]]}
+
+### st_flip_coordinates ###
+* Return the geometry with X and Y coordinates swapped.
+
+* Example:
+  * Command:
+
+        st_flip_coordinates(st_geom_from_text('POINT(1 2)'));
+  * Result:
+
+        {"type":"Point","coordinates":[2,1]}
+
+### st_buffer ###
+* Return a geometry that represents all points whose distance from the input 
geometry is less than or equal to the specified distance.
+
+* Example:
+  * Command:
+
+        st_area(st_buffer(st_geom_from_text('POINT(0 0)'), 1.0)) > 3.0;
+  * Result:
+
+        true
+
 ### st_polygonize ###
 * Aggregate. Creates a GeometryCollection containing possible polygons formed 
from the constituent linework of a set of geometries.
 
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java
index 75927cc1ba..ba20fa4c3d 100644
--- 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java
@@ -27,17 +27,23 @@ import 
org.apache.asterix.geo.evaluators.functions.STAsBinaryDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STAsGeoJSONDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STAsTextDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STBoundaryDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STBufferDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STCentroidDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STContainsDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STConvexHullDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STCoordDimDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STCrossesDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STDWithinDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STDifferenceDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STDimensionDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STDisjointDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STDistanceDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STDistanceSphereDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STEndPointDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STEnvelopeDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STEqualsDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STExteriorRingDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STFlipCoordinatesDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STGeomFromTextDescriptor;
 import 
org.apache.asterix.geo.evaluators.functions.STGeomFromTextSRIDDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STGeomFromWKBDescriptor;
@@ -51,6 +57,7 @@ import 
org.apache.asterix.geo.evaluators.functions.STIsCollectionDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STIsEmptyDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STIsRingDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STIsSimpleDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STIsValidDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STLengthDescriptor;
 import 
org.apache.asterix.geo.evaluators.functions.STLineFromMultiPointDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STMBRDescriptor;
@@ -68,6 +75,7 @@ import 
org.apache.asterix.geo.evaluators.functions.STOverlapsDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STPointNDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STPolygonizeDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STRelateDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STReverseDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STSRIDDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STStartPointDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STSymDifferenceDescriptor;
@@ -160,5 +168,13 @@ public class GeoFunctionRegistrant implements 
IFunctionRegistrant {
         fc.add(STPolygonizeDescriptor.FACTORY);
         fc.add(STMBRDescriptor.FACTORY);
         fc.add(STMBREnlargeDescriptor.FACTORY);
+        fc.add(STConvexHullDescriptor.FACTORY);
+        fc.add(STCentroidDescriptor.FACTORY);
+        fc.add(STIsValidDescriptor.FACTORY);
+        fc.add(STReverseDescriptor.FACTORY);
+        fc.add(STFlipCoordinatesDescriptor.FACTORY);
+        fc.add(STDistanceSphereDescriptor.FACTORY);
+        fc.add(STDWithinDescriptor.FACTORY);
+        fc.add(STBufferDescriptor.FACTORY);
     }
 }
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTGeometryNDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTGeometryNDescriptor.java
index c3096c45b1..a804631541 100644
--- 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTGeometryNDescriptor.java
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTGeometryNDescriptor.java
@@ -79,6 +79,7 @@ public abstract class AbstractSTGeometryNDescriptor extends 
AbstractScalarFuncti
 
         @Override
         public void evaluate(IFrameTupleReference tuple, IPointable result) 
throws HyracksDataException {
+            resultStorage.reset();
             eval.evaluate(tuple, inputArg);
             byte[] data = inputArg.getByteArray();
             int offset = inputArg.getStartOffset();
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTGeometryNDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STBufferDescriptor.java
similarity index 61%
copy from 
asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTGeometryNDescriptor.java
copy to 
asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STBufferDescriptor.java
index c3096c45b1..9af28b85d3 100644
--- 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTGeometryNDescriptor.java
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STBufferDescriptor.java
@@ -24,11 +24,15 @@ import java.io.DataOutput;
 import java.io.IOException;
 
 import 
org.apache.asterix.dataflow.data.nontagged.serde.AGeometrySerializerDeserializer;
-import 
org.apache.asterix.dataflow.data.nontagged.serde.AInt64SerializerDeserializer;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
 import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.EnumDeserializer;
+import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
 import 
org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
 import org.apache.asterix.runtime.exceptions.InvalidDataFormatException;
 import org.apache.asterix.runtime.exceptions.TypeMismatchException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
 import org.apache.hyracks.api.context.IEvaluatorContext;
@@ -39,11 +43,16 @@ import 
org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
 import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
 import org.locationtech.jts.geom.Geometry;
 
-public abstract class AbstractSTGeometryNDescriptor extends 
AbstractScalarFunctionDynamicDescriptor {
+public class STBufferDescriptor extends 
AbstractScalarFunctionDynamicDescriptor {
+
+    public static final IFunctionDescriptorFactory FACTORY = 
STBufferDescriptor::new;
 
     private static final long serialVersionUID = 1L;
 
-    abstract protected Geometry evaluateOGCGeometry(Geometry geometry, int n) 
throws HyracksDataException;
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_BUFFER;
+    }
 
     @Override
     public IScalarEvaluatorFactory createEvaluatorFactory(final 
IScalarEvaluatorFactory[] args) {
@@ -52,65 +61,59 @@ public abstract class AbstractSTGeometryNDescriptor extends 
AbstractScalarFuncti
 
             @Override
             public IScalarEvaluator createScalarEvaluator(IEvaluatorContext 
ctx) throws HyracksDataException {
-
-                return new AbstractSTGeometryNEvaluator(args, ctx);
+                return new STBufferEvaluator(args, ctx);
             }
         };
     }
 
-    private class AbstractSTGeometryNEvaluator implements IScalarEvaluator {
+    private class STBufferEvaluator implements IScalarEvaluator {
+        private final ArrayBackedValueStorage resultStorage;
+        private final DataOutput out;
+        private final IPointable inputArg0;
+        private final IScalarEvaluator eval0;
+        private final IPointable inputArg1;
+        private final IScalarEvaluator eval1;
 
-        private ArrayBackedValueStorage resultStorage;
-        private DataOutput out;
-        private IPointable inputArg;
-        private IScalarEvaluator eval;
-        private IPointable inputArg0;
-        private IScalarEvaluator eval0;
-
-        public AbstractSTGeometryNEvaluator(IScalarEvaluatorFactory[] args, 
IEvaluatorContext ctx)
-                throws HyracksDataException {
+        public STBufferEvaluator(IScalarEvaluatorFactory[] args, 
IEvaluatorContext ctx) throws HyracksDataException {
             resultStorage = new ArrayBackedValueStorage();
             out = resultStorage.getDataOutput();
-            inputArg = new VoidPointable();
-            eval = args[0].createScalarEvaluator(ctx);
             inputArg0 = new VoidPointable();
-            eval0 = args[1].createScalarEvaluator(ctx);
+            eval0 = args[0].createScalarEvaluator(ctx);
+            inputArg1 = new VoidPointable();
+            eval1 = args[1].createScalarEvaluator(ctx);
         }
 
         @Override
         public void evaluate(IFrameTupleReference tuple, IPointable result) 
throws HyracksDataException {
-            eval.evaluate(tuple, inputArg);
-            byte[] data = inputArg.getByteArray();
-            int offset = inputArg.getStartOffset();
-            int len = inputArg.getLength();
-
+            resultStorage.reset();
             eval0.evaluate(tuple, inputArg0);
-            byte[] data0 = inputArg0.getByteArray();
+            byte[] bytes0 = inputArg0.getByteArray();
             int offset0 = inputArg0.getStartOffset();
+            int len0 = inputArg0.getLength();
 
-            if (data[offset] != ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG) {
-                throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, 
data[offset],
+            eval1.evaluate(tuple, inputArg1);
+            byte[] bytes1 = inputArg1.getByteArray();
+            int offset1 = inputArg1.getStartOffset();
+
+            ATypeTag tag = 
EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(bytes0[offset0]);
+            if (tag != ATypeTag.GEOMETRY) {
+                throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, 
bytes0[offset0],
                         ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
             }
-            if (data0[offset0] != ATypeTag.SERIALIZED_INT64_TYPE_TAG) {
-                throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, 
data0[offset0],
-                        ATypeTag.SERIALIZED_INT64_TYPE_TAG);
-            }
 
-            ByteArrayInputStream inStream = new ByteArrayInputStream(data, 
offset + 1, len - 1);
-            DataInputStream dataIn = new DataInputStream(inStream);
-            Geometry geometry = 
AGeometrySerializerDeserializer.INSTANCE.deserialize(dataIn).getGeometry();
-            int n = (int) AInt64SerializerDeserializer.getLong(data0, offset0 
+ 1);
+            double distance = 
ATypeHierarchy.getDoubleValue(getIdentifier().getName(), 1, bytes1, offset1);
 
-            Geometry geometryN = evaluateOGCGeometry(geometry, n);
+            DataInputStream dataIn0 = new DataInputStream(new 
ByteArrayInputStream(bytes0, offset0 + 1, len0 - 1));
+            Geometry geometry = 
AGeometrySerializerDeserializer.INSTANCE.deserialize(dataIn0).getGeometry();
             try {
+                Geometry buffered = geometry.buffer(distance);
                 out.writeByte(ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
-                AGeometrySerializerDeserializer.INSTANCE.serialize(geometryN, 
out);
-                result.set(resultStorage);
+                AGeometrySerializerDeserializer.INSTANCE.serialize(buffered, 
out);
             } catch (IOException e) {
                 throw new InvalidDataFormatException(sourceLoc, 
getIdentifier(), e,
                         ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
             }
+            result.set(resultStorage);
         }
     }
 }
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STCentroidDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STCentroidDescriptor.java
new file mode 100644
index 0000000000..0d280daed6
--- /dev/null
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STCentroidDescriptor.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.locationtech.jts.geom.Geometry;
+
+public class STCentroidDescriptor extends AbstractSTSingleGeometryDescriptor {
+
+    private static final long serialVersionUID = 1L;
+    public static final IFunctionDescriptorFactory FACTORY = 
STCentroidDescriptor::new;
+
+    @Override
+    protected Object evaluateOGCGeometry(Geometry geometry) throws 
HyracksDataException {
+        return geometry.getCentroid();
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_CENTROID;
+    }
+
+}
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STConvexHullDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STConvexHullDescriptor.java
new file mode 100644
index 0000000000..9241ec8c5d
--- /dev/null
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STConvexHullDescriptor.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.locationtech.jts.geom.Geometry;
+
+public class STConvexHullDescriptor extends AbstractSTSingleGeometryDescriptor 
{
+
+    private static final long serialVersionUID = 1L;
+    public static final IFunctionDescriptorFactory FACTORY = 
STConvexHullDescriptor::new;
+
+    @Override
+    protected Object evaluateOGCGeometry(Geometry geometry) throws 
HyracksDataException {
+        return geometry.convexHull();
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_CONVEX_HULL;
+    }
+
+}
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STDWithinDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STDWithinDescriptor.java
new file mode 100644
index 0000000000..e623a51ccc
--- /dev/null
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STDWithinDescriptor.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import 
org.apache.asterix.dataflow.data.nontagged.serde.AGeometrySerializerDeserializer;
+import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
+import org.apache.asterix.om.base.ABoolean;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.EnumDeserializer;
+import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
+import 
org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.exceptions.InvalidDataFormatException;
+import org.apache.asterix.runtime.exceptions.TypeMismatchException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.context.IEvaluatorContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+import org.locationtech.jts.geom.Geometry;
+
+public class STDWithinDescriptor extends 
AbstractScalarFunctionDynamicDescriptor {
+
+    public static final IFunctionDescriptorFactory FACTORY = 
STDWithinDescriptor::new;
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_DWITHIN;
+    }
+
+    @Override
+    public IScalarEvaluatorFactory createEvaluatorFactory(final 
IScalarEvaluatorFactory[] args) {
+        return new IScalarEvaluatorFactory() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public IScalarEvaluator createScalarEvaluator(IEvaluatorContext 
ctx) throws HyracksDataException {
+                return new STDWithinEvaluator(args, ctx);
+            }
+        };
+    }
+
+    private class STDWithinEvaluator implements IScalarEvaluator {
+        private final ArrayBackedValueStorage resultStorage;
+        private final DataOutput out;
+        private final IPointable inputArg0;
+        private final IScalarEvaluator eval0;
+        private final IPointable inputArg1;
+        private final IScalarEvaluator eval1;
+        private final IPointable inputArg2;
+        private final IScalarEvaluator eval2;
+
+        public STDWithinEvaluator(IScalarEvaluatorFactory[] args, 
IEvaluatorContext ctx) throws HyracksDataException {
+            resultStorage = new ArrayBackedValueStorage();
+            out = resultStorage.getDataOutput();
+            inputArg0 = new VoidPointable();
+            eval0 = args[0].createScalarEvaluator(ctx);
+            inputArg1 = new VoidPointable();
+            eval1 = args[1].createScalarEvaluator(ctx);
+            inputArg2 = new VoidPointable();
+            eval2 = args[2].createScalarEvaluator(ctx);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void evaluate(IFrameTupleReference tuple, IPointable result) 
throws HyracksDataException {
+            resultStorage.reset();
+            eval0.evaluate(tuple, inputArg0);
+            byte[] bytes0 = inputArg0.getByteArray();
+            int offset0 = inputArg0.getStartOffset();
+            int len0 = inputArg0.getLength();
+
+            eval1.evaluate(tuple, inputArg1);
+            byte[] bytes1 = inputArg1.getByteArray();
+            int offset1 = inputArg1.getStartOffset();
+            int len1 = inputArg1.getLength();
+
+            eval2.evaluate(tuple, inputArg2);
+            byte[] bytes2 = inputArg2.getByteArray();
+            int offset2 = inputArg2.getStartOffset();
+
+            ATypeTag tag = 
EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(bytes0[offset0]);
+            if (tag != ATypeTag.GEOMETRY) {
+                throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, 
bytes0[offset0],
+                        ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
+            }
+            tag = 
EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(bytes1[offset1]);
+            if (tag != ATypeTag.GEOMETRY) {
+                throw new TypeMismatchException(sourceLoc, getIdentifier(), 1, 
bytes1[offset1],
+                        ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
+            }
+
+            double distance = 
ATypeHierarchy.getDoubleValue(getIdentifier().getName(), 2, bytes2, offset2);
+
+            DataInputStream dataIn0 = new DataInputStream(new 
ByteArrayInputStream(bytes0, offset0 + 1, len0 - 1));
+            Geometry geometry0 = 
AGeometrySerializerDeserializer.INSTANCE.deserialize(dataIn0).getGeometry();
+            DataInputStream dataIn1 = new DataInputStream(new 
ByteArrayInputStream(bytes1, offset1 + 1, len1 - 1));
+            Geometry geometry1 = 
AGeometrySerializerDeserializer.INSTANCE.deserialize(dataIn1).getGeometry();
+            try {
+                boolean val = geometry0.isWithinDistance(geometry1, distance);
+                
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ABOOLEAN)
+                        .serialize(val ? ABoolean.TRUE : ABoolean.FALSE, out);
+            } catch (IOException e) {
+                throw new InvalidDataFormatException(sourceLoc, 
getIdentifier(), e,
+                        ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
+            }
+            result.set(resultStorage);
+        }
+    }
+}
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STDistanceSphereDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STDistanceSphereDescriptor.java
new file mode 100644
index 0000000000..b882dd9ae4
--- /dev/null
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STDistanceSphereDescriptor.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+
+public class STDistanceSphereDescriptor extends 
AbstractSTDoubleGeometryDescriptor {
+
+    private static final long serialVersionUID = 1L;
+    public static final IFunctionDescriptorFactory FACTORY = 
STDistanceSphereDescriptor::new;
+
+    private static final double EARTH_RADIUS_METERS = 6371008.0;
+
+    @Override
+    protected Object evaluateOGCGeometry(Geometry geometry0, Geometry 
geometry1) throws HyracksDataException {
+        Coordinate c0 = geometry0.getCoordinate();
+        Coordinate c1 = geometry1.getCoordinate();
+        return haversineDistance(c0.y, c0.x, c1.y, c1.x);
+    }
+
+    private static double haversineDistance(double lat1, double lon1, double 
lat2, double lon2) {
+        double dLat = Math.toRadians(lat2 - lat1);
+        double dLon = Math.toRadians(lon2 - lon1);
+        double rLat1 = Math.toRadians(lat1);
+        double rLat2 = Math.toRadians(lat2);
+
+        double a =
+                Math.pow(Math.sin(dLat / 2), 2) + Math.cos(rLat1) * 
Math.cos(rLat2) * Math.pow(Math.sin(dLon / 2), 2);
+        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+        return EARTH_RADIUS_METERS * c;
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_DISTANCE_SPHERE;
+    }
+
+}
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STFlipCoordinatesDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STFlipCoordinatesDescriptor.java
new file mode 100644
index 0000000000..7ad3277189
--- /dev/null
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STFlipCoordinatesDescriptor.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.locationtech.jts.geom.CoordinateSequence;
+import org.locationtech.jts.geom.CoordinateSequenceFilter;
+import org.locationtech.jts.geom.Geometry;
+
+public class STFlipCoordinatesDescriptor extends 
AbstractSTSingleGeometryDescriptor {
+
+    private static final long serialVersionUID = 1L;
+    public static final IFunctionDescriptorFactory FACTORY = 
STFlipCoordinatesDescriptor::new;
+
+    @Override
+    protected Object evaluateOGCGeometry(Geometry geometry) throws 
HyracksDataException {
+        Geometry flipped = geometry.copy();
+        flipped.apply(FlipCoordinatesFilter.INSTANCE);
+        return flipped;
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_FLIP_COORDINATES;
+    }
+
+    private static final class FlipCoordinatesFilter implements 
CoordinateSequenceFilter {
+        private static final FlipCoordinatesFilter INSTANCE = new 
FlipCoordinatesFilter();
+
+        @Override
+        public void filter(CoordinateSequence seq, int i) {
+
+            double x = seq.getX(i);
+            double y = seq.getY(i);
+            seq.setOrdinate(i, CoordinateSequence.X, y);
+            seq.setOrdinate(i, CoordinateSequence.Y, x);
+        }
+
+        @Override
+        public boolean isDone() {
+            return false;
+        }
+
+        @Override
+        public boolean isGeometryChanged() {
+            return true;
+        }
+    }
+
+}
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STIsValidDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STIsValidDescriptor.java
new file mode 100644
index 0000000000..3f9f4cb4bc
--- /dev/null
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STIsValidDescriptor.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.locationtech.jts.geom.Geometry;
+
+public class STIsValidDescriptor extends AbstractSTSingleGeometryDescriptor {
+
+    private static final long serialVersionUID = 1L;
+    public static final IFunctionDescriptorFactory FACTORY = 
STIsValidDescriptor::new;
+
+    @Override
+    protected Object evaluateOGCGeometry(Geometry geometry) throws 
HyracksDataException {
+        return geometry.isValid();
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_IS_VALID;
+    }
+
+}
diff --git 
a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STReverseDescriptor.java
 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STReverseDescriptor.java
new file mode 100644
index 0000000000..93935fb93c
--- /dev/null
+++ 
b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STReverseDescriptor.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.locationtech.jts.geom.Geometry;
+
+public class STReverseDescriptor extends AbstractSTSingleGeometryDescriptor {
+
+    private static final long serialVersionUID = 1L;
+    public static final IFunctionDescriptorFactory FACTORY = 
STReverseDescriptor::new;
+
+    @Override
+    protected Object evaluateOGCGeometry(Geometry geometry) throws 
HyracksDataException {
+        return geometry.reverse();
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_REVERSE;
+    }
+
+}
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index 51ad36b4bd..144a389a36 100644
--- 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -1128,6 +1128,16 @@ public class BuiltinFunctions {
     public static final FunctionIdentifier ST_MBR = 
FunctionConstants.newAsterix("st-mbr", 1);
     public static final FunctionIdentifier ST_MBR_ENLARGE = 
FunctionConstants.newAsterix("st-mbr-enlarge", 2);
 
+    public static final FunctionIdentifier ST_CONVEX_HULL = 
FunctionConstants.newAsterix("st-convex-hull", 1);
+    public static final FunctionIdentifier ST_CENTROID = 
FunctionConstants.newAsterix("st-centroid", 1);
+    public static final FunctionIdentifier ST_IS_VALID = 
FunctionConstants.newAsterix("st-is-valid", 1);
+    public static final FunctionIdentifier ST_REVERSE = 
FunctionConstants.newAsterix("st-reverse", 1);
+    public static final FunctionIdentifier ST_FLIP_COORDINATES = 
FunctionConstants.newAsterix("st-flip-coordinates", 1);
+    public static final FunctionIdentifier ST_SET_SRID = 
FunctionConstants.newAsterix("st-set-srid", 2);
+    public static final FunctionIdentifier ST_DISTANCE_SPHERE = 
FunctionConstants.newAsterix("st-distance-sphere", 2);
+    public static final FunctionIdentifier ST_DWITHIN = 
FunctionConstants.newAsterix("st-dwithin", 3);
+    public static final FunctionIdentifier ST_BUFFER = 
FunctionConstants.newAsterix("st-buffer", 2);
+
     // Spatial and temporal type accessors
     public static final FunctionIdentifier ACCESSOR_TEMPORAL_YEAR = 
FunctionConstants.newAsterix("get-year", 1);
     public static final FunctionIdentifier ACCESSOR_TEMPORAL_MONTH = 
FunctionConstants.newAsterix("get-month", 1);
@@ -2009,6 +2019,15 @@ public class BuiltinFunctions {
         addPrivateFunction(ST_MBR, ARectangleTypeComputer.INSTANCE, true);
         addPrivateFunction(ST_MBR_ENLARGE, ARectangleTypeComputer.INSTANCE, 
true);
 
+        addFunction(ST_CONVEX_HULL, AGeometryTypeComputer.INSTANCE, true);
+        addFunction(ST_CENTROID, AGeometryTypeComputer.INSTANCE, true);
+        addFunction(ST_IS_VALID, ABooleanTypeComputer.INSTANCE, true);
+        addFunction(ST_REVERSE, AGeometryTypeComputer.INSTANCE, true);
+        addFunction(ST_FLIP_COORDINATES, AGeometryTypeComputer.INSTANCE, true);
+        addFunction(ST_DISTANCE_SPHERE, ADoubleTypeComputer.INSTANCE, true);
+        addFunction(ST_DWITHIN, ABooleanTypeComputer.INSTANCE, true);
+        addFunction(ST_BUFFER, AGeometryTypeComputer.INSTANCE, true);
+
         // Binary functions
         addFunction(BINARY_HEX_CONSTRUCTOR, 
ABinaryTypeComputer.INSTANCE_NULLABLE, true);
         addFunction(BINARY_BASE64_CONSTRUCTOR, 
ABinaryTypeComputer.INSTANCE_NULLABLE, true);

Reply via email to