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);
