From c54f755d593c4c6545ef898165cb09bbc3629e95 Mon Sep 17 00:00:00 2001 From: Max Gabrielsson Date: Sat, 4 Nov 2023 17:49:44 +0100 Subject: [PATCH 1/3] fix some warnings, should compile on gcc now --- .../spatial/core/functions/scalar/st_exteriorring.cpp | 2 +- .../spatial/core/functions/scalar/st_makepolygon.cpp | 2 +- spatial/src/spatial/gdal/functions/st_read.cpp | 2 +- spatial/src/spatial/geos/geos_wrappers.cpp | 10 +++++----- spatial/src/spatial/proj/functions.cpp | 10 ++++++---- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/spatial/src/spatial/core/functions/scalar/st_exteriorring.cpp b/spatial/src/spatial/core/functions/scalar/st_exteriorring.cpp index 0c16cc23..6127b2fb 100644 --- a/spatial/src/spatial/core/functions/scalar/st_exteriorring.cpp +++ b/spatial/src/spatial/core/functions/scalar/st_exteriorring.cpp @@ -113,7 +113,7 @@ static void GeometryExteriorRingFunction(DataChunk &args, ExpressionState &state auto num_points = shell.Count(); auto line = lstate.factory.CreateLineString(num_points); - for (auto i = 0; i < num_points; i++) { + for (uint32_t i = 0; i < num_points; i++) { line.Vertices().Add(shell[i]); } return lstate.factory.Serialize(result, Geometry(line)); diff --git a/spatial/src/spatial/core/functions/scalar/st_makepolygon.cpp b/spatial/src/spatial/core/functions/scalar/st_makepolygon.cpp index 3c4ad112..181fb921 100644 --- a/spatial/src/spatial/core/functions/scalar/st_makepolygon.cpp +++ b/spatial/src/spatial/core/functions/scalar/st_makepolygon.cpp @@ -81,7 +81,7 @@ static void MakePolygonFromRingsFunction(DataChunk &args, ExpressionState &state auto polygon = lstate.factory.CreatePolygon(rings_counts.size(), rings_counts.data()); - for (auto ring_idx = 0; ring_idx < rings.size(); ring_idx++) { + for (idx_t ring_idx = 0; ring_idx < rings.size(); ring_idx++) { auto &new_ring = rings[ring_idx]; auto &poly_ring = polygon.Ring(ring_idx); for (auto &v : new_ring.Vertices()) { diff --git a/spatial/src/spatial/gdal/functions/st_read.cpp b/spatial/src/spatial/gdal/functions/st_read.cpp index 6f6b79d0..c9e3ca29 100644 --- a/spatial/src/spatial/gdal/functions/st_read.cpp +++ b/spatial/src/spatial/gdal/functions/st_read.cpp @@ -579,7 +579,7 @@ void GdalTableFunction::Scan(ClientContext &context, TableFunctionInput &input, if (!data.keep_wkb) { // Find the geometry columns - for (auto col_idx = 0; col_idx < state.column_ids.size(); col_idx++) { + for (idx_t col_idx = 0; col_idx < state.column_ids.size(); col_idx++) { auto mapped_idx = state.column_ids[col_idx]; if (data.geometry_column_ids.find(mapped_idx) != data.geometry_column_ids.end()) { // Found a geometry column diff --git a/spatial/src/spatial/geos/geos_wrappers.cpp b/spatial/src/spatial/geos/geos_wrappers.cpp index 79687f9b..d047db84 100644 --- a/spatial/src/spatial/geos/geos_wrappers.cpp +++ b/spatial/src/spatial/geos/geos_wrappers.cpp @@ -338,7 +338,7 @@ static void SerializePolygon(Cursor &writer, const GEOSGeometry *geom, const GEO return; } - auto num_holes = GEOSGetNumInteriorRings_r(ctx, geom); + uint32_t num_holes = GEOSGetNumInteriorRings_r(ctx, geom); writer.Write(num_holes + 1); // +1 for the shell // Get shell @@ -393,7 +393,7 @@ static void SerializePolygon(Cursor &writer, const GEOSGeometry *geom, const GEO static void SerializeMultiPoint(Cursor &writer, const GEOSGeometry *geom, const GEOSContextHandle_t ctx) { writer.Write((uint32_t)GeometryType::MULTIPOINT); - auto num_points = GEOSGetNumGeometries_r(ctx, geom); + uint32_t num_points = GEOSGetNumGeometries_r(ctx, geom); writer.Write(num_points); for (uint32_t i = 0; i < num_points; i++) { auto point = GEOSGetGeometryN_r(ctx, geom, i); @@ -403,7 +403,7 @@ static void SerializeMultiPoint(Cursor &writer, const GEOSGeometry *geom, const static void SerializeMultiLineString(Cursor &writer, const GEOSGeometry *geom, const GEOSContextHandle_t ctx) { writer.Write((uint32_t)GeometryType::MULTILINESTRING); - auto num_linestrings = GEOSGetNumGeometries_r(ctx, geom); + uint32_t num_linestrings = GEOSGetNumGeometries_r(ctx, geom); writer.Write(num_linestrings); for (uint32_t i = 0; i < num_linestrings; i++) { auto linestring = GEOSGetGeometryN_r(ctx, geom, i); @@ -413,7 +413,7 @@ static void SerializeMultiLineString(Cursor &writer, const GEOSGeometry *geom, c static void SerializeMultiPolygon(Cursor &writer, const GEOSGeometry *geom, const GEOSContextHandle_t ctx) { writer.Write((uint32_t)GeometryType::MULTIPOLYGON); - auto num_polygons = GEOSGetNumGeometries_r(ctx, geom); + uint32_t num_polygons = GEOSGetNumGeometries_r(ctx, geom); writer.Write(num_polygons); for (uint32_t i = 0; i < num_polygons; i++) { auto polygon = GEOSGetGeometryN_r(ctx, geom, i); @@ -423,7 +423,7 @@ static void SerializeMultiPolygon(Cursor &writer, const GEOSGeometry *geom, cons static void SerializeGeometryCollection(Cursor &writer, const GEOSGeometry *geom, const GEOSContextHandle_t ctx) { writer.Write((uint32_t)GeometryType::GEOMETRYCOLLECTION); - auto num_geometries = GEOSGetNumGeometries_r(ctx, geom); + uint32_t num_geometries = GEOSGetNumGeometries_r(ctx, geom); writer.Write(num_geometries); for (uint32_t i = 0; i < num_geometries; i++) { auto geometry = GEOSGetGeometryN_r(ctx, geom, i); diff --git a/spatial/src/spatial/proj/functions.cpp b/spatial/src/spatial/proj/functions.cpp index 3a2891cc..5900cdcd 100644 --- a/spatial/src/spatial/proj/functions.cpp +++ b/spatial/src/spatial/proj/functions.cpp @@ -32,7 +32,8 @@ struct ProjFunctionLocalState : public FunctionLocalState { static unique_ptr Init(ExpressionState &state, const BoundFunctionExpression &expr, FunctionData *bind_data) { - return make_uniq(state.GetContext()); + auto result = make_uniq(state.GetContext()); + return std::move(result); } static ProjFunctionLocalState &ResetAndGet(ExpressionState &state) { @@ -50,7 +51,7 @@ struct TransformFunctionData : FunctionData { unique_ptr Copy() const override { auto result = make_uniq(); result->conventional_gis_order = conventional_gis_order; - return result; + return std::move(result); } bool Equals(const FunctionData &other) const override { auto &data = other.Cast(); @@ -73,7 +74,7 @@ static unique_ptr TransformBind(ClientContext &context, ScalarFunc } result->conventional_gis_order = BooleanValue::Get(ExpressionExecutor::EvaluateScalar(context, *arg)); } - return result; + return std::move(result); } static void Box2DTransformFunction(DataChunk &args, ExpressionState &state, Vector &result) { @@ -441,7 +442,8 @@ unique_ptr GenerateSpatialRefSysTable::Bind(ClientContext &context unique_ptr GenerateSpatialRefSysTable::Init(ClientContext &context, TableFunctionInitInput &input) { - return make_uniq(); + auto result = make_uniq(); + return std::move(result); } void GenerateSpatialRefSysTable::Execute(ClientContext &context, TableFunctionInput &input, DataChunk &output) { From 06896ab6e7790964ee6c5bbc6dfb83321d1eac56 Mon Sep 17 00:00:00 2001 From: Max Gabrielsson Date: Sat, 4 Nov 2023 18:09:29 +0100 Subject: [PATCH 2/3] add st_linmerge --- README.md | 1 + .../include/spatial/geos/functions/scalar.hpp | 2 + .../geos/functions/scalar/CMakeLists.txt | 1 + .../geos/functions/scalar/st_linemerge.cpp | 51 +++++++++++++++++++ test/sql/postgis/st_linemerge.test | 31 +++++++++++ 5 files changed, 86 insertions(+) create mode 100644 spatial/src/spatial/geos/functions/scalar/st_linemerge.cpp create mode 100644 test/sql/postgis/st_linemerge.test diff --git a/README.md b/README.md index a21e86a0..574fe0cd 100644 --- a/README.md +++ b/README.md @@ -376,6 +376,7 @@ Again, please feel free to open an issue if there is a particular function you w | ST_IsSimple | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | | ST_IsValid | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | | ST_Length | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | +| ST_LineMerge | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | | ST_Normalize | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | | ST_NumPoints/ST_NPoints | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | | ST_Overlaps | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | diff --git a/spatial/include/spatial/geos/functions/scalar.hpp b/spatial/include/spatial/geos/functions/scalar.hpp index fd26abd4..09c5a81f 100644 --- a/spatial/include/spatial/geos/functions/scalar.hpp +++ b/spatial/include/spatial/geos/functions/scalar.hpp @@ -30,6 +30,7 @@ struct GEOSScalarFunctions { RegisterStIsRing(db); RegisterStIsSimple(db); RegisterStIsValid(db); + RegisterStLineMerge(db); RegisterStNormalize(db); RegisterStOverlaps(db); RegisterStPointOnSurface(db); @@ -72,6 +73,7 @@ struct GEOSScalarFunctions { static void RegisterStReducePrecision(DatabaseInstance &db); static void RegisterStRemoveRepeatedPoints(DatabaseInstance &db); static void RegisterStReverse(DatabaseInstance &db); + static void RegisterStLineMerge(DatabaseInstance &db); static void RegisterStSimplifyPreserveTopology(DatabaseInstance &db); static void RegisterStSimplify(DatabaseInstance &db); static void RegisterStTouches(DatabaseInstance &db); diff --git a/spatial/src/spatial/geos/functions/scalar/CMakeLists.txt b/spatial/src/spatial/geos/functions/scalar/CMakeLists.txt index ebaf62ff..35458f54 100644 --- a/spatial/src/spatial/geos/functions/scalar/CMakeLists.txt +++ b/spatial/src/spatial/geos/functions/scalar/CMakeLists.txt @@ -22,6 +22,7 @@ set(EXTENSION_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/st_is_ring.cpp ${CMAKE_CURRENT_SOURCE_DIR}/st_is_simple.cpp ${CMAKE_CURRENT_SOURCE_DIR}/st_is_valid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/st_linemerge.cpp ${CMAKE_CURRENT_SOURCE_DIR}/st_normalize.cpp ${CMAKE_CURRENT_SOURCE_DIR}/st_overlaps.cpp ${CMAKE_CURRENT_SOURCE_DIR}/st_pointonsurface.cpp diff --git a/spatial/src/spatial/geos/functions/scalar/st_linemerge.cpp b/spatial/src/spatial/geos/functions/scalar/st_linemerge.cpp new file mode 100644 index 00000000..31e3d354 --- /dev/null +++ b/spatial/src/spatial/geos/functions/scalar/st_linemerge.cpp @@ -0,0 +1,51 @@ +#include "spatial/common.hpp" +#include "spatial/core/types.hpp" +#include "spatial/geos/functions/scalar.hpp" +#include "spatial/geos/functions/common.hpp" +#include "spatial/geos/geos_wrappers.hpp" + +#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" +#include "duckdb/common/vector_operations/unary_executor.hpp" +#include "duckdb/common/vector_operations/binary_executor.hpp" + +namespace spatial { + +namespace geos { + +using namespace spatial::core; + +static void LineMergeFunction(DataChunk &args, ExpressionState &state, Vector &result) { + auto &lstate = GEOSFunctionLocalState::ResetAndGet(state); + auto &ctx = lstate.ctx.GetCtx(); + UnaryExecutor::Execute(args.data[0], result, args.size(), [&](string_t &geometry_blob) { + auto geometry = lstate.ctx.Deserialize(geometry_blob); + auto convex_hull_geometry = make_uniq_geos(ctx, GEOSLineMerge_r(ctx, geometry.get())); + return lstate.ctx.Serialize(result, convex_hull_geometry); + }); +} + +static void LineMergeFunctionWithDirected(DataChunk &args, ExpressionState &state, Vector &result) { + auto &lstate = GEOSFunctionLocalState::ResetAndGet(state); + auto &ctx = lstate.ctx.GetCtx(); + BinaryExecutor::Execute(args.data[0], args.data[1], result, args.size(), [&](string_t &geometry_blob, bool directed) { + auto geometry = lstate.ctx.Deserialize(geometry_blob); + auto convex_hull_geometry = directed ? make_uniq_geos(ctx, GEOSLineMergeDirected_r(ctx, geometry.get())) + : make_uniq_geos(ctx, GEOSLineMerge_r(ctx, geometry.get())); + + return lstate.ctx.Serialize(result, convex_hull_geometry); + }); +} + +void GEOSScalarFunctions::RegisterStLineMerge(DatabaseInstance &db) { + + ScalarFunctionSet set("ST_LineMerge"); + + set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY()}, GeoTypes::GEOMETRY(), LineMergeFunction, nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); + set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY(), LogicalType::BOOLEAN}, GeoTypes::GEOMETRY(), LineMergeFunctionWithDirected, nullptr, nullptr, nullptr, GEOSFunctionLocalState::Init)); + + ExtensionUtil::RegisterFunction(db, set); +} + +} // namespace geos + +} // namespace spatial diff --git a/test/sql/postgis/st_linemerge.test b/test/sql/postgis/st_linemerge.test new file mode 100644 index 00000000..935c2e39 --- /dev/null +++ b/test/sql/postgis/st_linemerge.test @@ -0,0 +1,31 @@ +# Example taken from the PostGIS manual @ http://postgis.net, licensed under the Creative Commons Attribution-Share Alike 3.0 License. + +require spatial + +query I +SELECT ST_AsText(ST_LineMerge(ST_GeomFromText('MULTILINESTRING((10 160, 60 120), (120 140, 60 120), (120 140, 180 120))'))); +---- +LINESTRING (10 160, 60 120, 120 140, 180 120) + +query I +SELECT ST_AsText(ST_LineMerge(ST_GeomFromText('MULTILINESTRING((10 160, 60 120), (120 140, 60 120), (120 140, 180 120), (100 180, 120 140))'))); +---- +MULTILINESTRING ((10 160, 60 120, 120 140), (100 180, 120 140), (120 140, 180 120)) + +query I +SELECT ST_AsText(ST_LineMerge(ST_GeomFromText('MULTILINESTRING((-29 -27,-30 -29.7,-36 -31,-45 -33),(-45.2 -33.2,-46 -32))'))); +---- +MULTILINESTRING ((-45.2 -33.2, -46 -32), (-29 -27, -30 -29.7, -36 -31, -45 -33)) + +query I +SELECT ST_AsText(ST_LineMerge(ST_GeomFromText('MULTILINESTRING((60 30, 10 70), (120 50, 60 30), (120 50, 180 30))'), true)); +---- +MULTILINESTRING ((120 50, 60 30, 10 70), (120 50, 180 30)) + +# We dont handle Z yet +# query I +# SELECT ST_AsText(ST_LineMerge( +# 'MULTILINESTRING((-29 -27 11,-30 -29.7 10,-36 -31 5,-45 -33 6), (-29 -27 12,-30 -29.7 5), (-45 -33 1,-46 -32 11))' +# )); +# ---- +# LINESTRING Z (-30 -29.7 5,-29 -27 11,-30 -29.7 10,-36 -31 5,-45 -33 1,-46 -32 11) \ No newline at end of file From 82df47bdfed672ac68f66e899226acaec0401fd7 Mon Sep 17 00:00:00 2001 From: Max Gabrielsson Date: Sat, 4 Nov 2023 18:13:34 +0100 Subject: [PATCH 3/3] update docs --- README.md | 107 +++++++++++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 574fe0cd..8d721d9a 100644 --- a/README.md +++ b/README.md @@ -336,56 +336,57 @@ We are actively working on implementing more functions, and will update this tab Again, please feel free to open an issue if there is a particular function you would like to see implemented. Contributions are also welcome! -| Scalar functions | GEOMETRY | POINT_2D | LINESTRING_2D | POLYGON_2D | BOX_2D | -| --------------------------- | -------- | ---------- | ------------- | ---------- | --------------- | -| ST_Point | 🦆 | 🦆 | | | | -| ST_Area | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_AsGeoJSON | 🦆 | 🦆 | 🦆 | 🦆. | 🦆 | -| ST_AsHEXWKB | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_AsText | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_AsWKB | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_Boundary | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Buffer | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Centroid | 🧭 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_Collect | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_CollectionExtract | 🦆 | | | | | -| ST_Contains | 🧭 | 🔄 | 🔄 | 🦆 or 🔄 | 🔄 (as POLYGON) | -| ST_ContainsProperly | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_ConvexHull | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_CoveredBy | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Covers | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Crosses | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Difference | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Dimension | 🦆 | | | | | -| ST_Disjoint | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Distance | 🧭 | 🦆 or 🔄 | 🦆 or 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_DWithin | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Envelope | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Equals | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_FlipCoordinates | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_GeomFromText | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_GeomFromWKB | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | -| ST_GeometryType | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | -| ST_MakeLine | 🦆 | | 🦆 | | | -| ST_Perimeter | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_Intersection | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Intersects | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_IsClosed | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_IsEmpty | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | -| ST_IsRing | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_IsSimple | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_IsValid | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Length | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | -| ST_LineMerge | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Normalize | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_NumPoints/ST_NPoints | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | -| ST_Overlaps | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_PointOnSurface | 🧭 | 🧭 | 🧭 | 🧭 | 🔄 (as POLYGON) | -| ST_RemoveRepeatedPoints | 🧭 | | 🦆 | 🔄 | | -| ST_SimplifyPreserveTopology | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Simplify | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Touches | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Union | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Within | 🧭 | 🦆 or 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_X | 🧭 | 🦆 | 🔄 | 🔄 | 🔄 (as POLYGON) | -| ST_Y | 🧭 | 🦆 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| Scalar functions | GEOMETRY | POINT_2D | LINESTRING_2D | POLYGON_2D | BOX_2D | +|-----------------------------|----------|----------|---------------|------------|-----------------| +| ST_Point | 🦆 | 🦆 | | | | +| ST_Area | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | +| ST_AsGeoJSON | 🦆 | 🦆 | 🦆 | 🦆. | 🦆 | +| ST_AsHEXWKB | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | +| ST_AsText | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | +| ST_AsWKB | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | +| ST_Boundary | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Buffer | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Centroid | 🧭 | 🦆 | 🦆 | 🦆 | 🦆 | +| ST_Collect | 🦆 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_CollectionExtract | 🦆 | | | | | +| ST_Contains | 🧭 | 🔄 | 🔄 | 🦆 or 🔄 | 🔄 (as POLYGON) | +| ST_ContainsProperly | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_ConvexHull | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_CoveredBy | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Covers | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Crosses | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Difference | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Dimension | 🦆 | | | | | +| ST_Disjoint | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Distance | 🧭 | 🦆 or 🔄 | 🦆 or 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Dump | 🦆 | | | | | +| ST_DWithin | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Envelope | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Equals | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_FlipCoordinates | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | +| ST_GeomFromText | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_GeomFromWKB | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | +| ST_GeometryType | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | +| ST_MakeLine | 🦆 | | 🦆 | | | +| ST_Perimeter | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | +| ST_Intersection | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Intersects | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_IsClosed | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_IsEmpty | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | +| ST_IsRing | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_IsSimple | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_IsValid | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Length | 🦆 | 🦆 | 🦆 | 🦆 | 🔄 (as POLYGON) | +| ST_LineMerge | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Normalize | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_NumPoints/ST_NPoints | 🦆 | 🦆 | 🦆 | 🦆 | 🦆 | +| ST_Overlaps | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_PointOnSurface | 🧭 | 🧭 | 🧭 | 🧭 | 🔄 (as POLYGON) | +| ST_RemoveRepeatedPoints | 🧭 | | 🦆 | 🔄 | | +| ST_SimplifyPreserveTopology | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Simplify | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Touches | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Union | 🧭 | 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Within | 🧭 | 🦆 or 🔄 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_X | 🧭 | 🦆 | 🔄 | 🔄 | 🔄 (as POLYGON) | +| ST_Y | 🧭 | 🦆 | 🔄 | 🔄 | 🔄 (as POLYGON) |