Skip to content

Commit

Permalink
Merge pull request #403 from Maxxen/dev
Browse files Browse the repository at this point in the history
Add `ST_Multi`
  • Loading branch information
Maxxen authored Sep 19, 2024
2 parents 7071f7a + edb431a commit 5ec66ad
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 0 deletions.
31 changes: 31 additions & 0 deletions docs/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
| [`ST_MakeLine`](#st_makeline) | Creates a LINESTRING geometry from a pair or list of input points |
| [`ST_MakePolygon`](#st_makepolygon) | Creates a polygon from a shell geometry and an optional set of holes |
| [`ST_MakeValid`](#st_makevalid) | Attempts to make an invalid geometry valid without removing any vertices |
| [`ST_Multi`](#st_multi) | Turns a single geometry into a multi geometry. |
| [`ST_NGeometries`](#st_ngeometries) | Returns the number of component geometries in a collection geometry. |
| [`ST_NInteriorRings`](#st_ninteriorrings) | Returns the number if interior rings of a polygon |
| [`ST_NPoints`](#st_npoints) | Returns the number of vertices within a geometry |
Expand Down Expand Up @@ -1431,6 +1432,36 @@ Attempts to make an invalid geometry valid without removing any vertices

----

### ST_Multi


#### Signature

```sql
GEOMETRY ST_Multi (col0 GEOMETRY)
```

#### Description

Turns a single geometry into a multi geometry.

If the geometry is already a multi geometry, it is returned as is.

#### Example

```sql
SELECT ST_Multi(ST_GeomFromText('POINT(1 2)'));
-- MULTIPOINT (1 2)

SELECT ST_Multi(ST_GeomFromText('LINESTRING(1 1, 2 2)'));
-- MULTILINESTRING ((1 1, 2 2))

SELECT ST_Multi(ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'));
-- MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)))
```

----

### ST_NGeometries


Expand Down
4 changes: 4 additions & 0 deletions spatial/include/spatial/core/functions/scalar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct CoreScalarFunctions {
RegisterStMakeEnvelope(db);
RegisterStMakeLine(db);
RegisterStMakePolygon(db);
RegisterStMulti(db);
RegisterStNGeometries(db);
RegisterStNInteriorRings(db);
RegisterStNPoints(db);
Expand Down Expand Up @@ -165,6 +166,9 @@ struct CoreScalarFunctions {
// ST_MakePolygon
static void RegisterStMakePolygon(DatabaseInstance &db);

// ST_Multi
static void RegisterStMulti(DatabaseInstance &db);

// ST_NGeometries
static void RegisterStNGeometries(DatabaseInstance &db);

Expand Down
1 change: 1 addition & 0 deletions spatial/src/spatial/core/functions/scalar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ set(EXTENSION_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/st_makeenvelope.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_makeline.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_makepolygon.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_multi.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_ngeometries.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_ninteriorrings.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_npoints.cpp
Expand Down
83 changes: 83 additions & 0 deletions spatial/src/spatial/core/functions/scalar/st_multi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include "duckdb/common/vector_operations/generic_executor.hpp"
#include "spatial/common.hpp"
#include "spatial/core/functions/scalar.hpp"
#include "spatial/core/functions/common.hpp"
#include "spatial/core/geometry/geometry.hpp"
#include "spatial/core/types.hpp"
#include "spatial/core/geometry/geometry_processor.hpp"

namespace spatial {

namespace core {

//------------------------------------------------------------------------------
// GEOMETRY
//------------------------------------------------------------------------------

static void GeometryMultiFunction(DataChunk &args, ExpressionState &state, Vector &result) {
auto &lstate = GeometryFunctionLocalState::ResetAndGet(state);
auto &arena = lstate.arena;
auto &input = args.data[0];

UnaryExecutor::Execute<geometry_t, geometry_t>(input, result, args.size(), [&](const geometry_t &geom_blob) {

const bool has_z = geom_blob.GetProperties().HasZ();
const bool has_m = geom_blob.GetProperties().HasM();

switch(geom_blob.GetType()) {
case GeometryType::POINT: {
auto mpoint = MultiPoint::Create(arena, 1, has_z, has_m);
MultiPoint::Part(mpoint, 0) = Geometry::Deserialize(arena, geom_blob);
return Geometry::Serialize(mpoint, result);
}
case GeometryType::LINESTRING: {
auto mline = MultiLineString::Create(arena, 1, has_z, has_m);
MultiLineString::Part(mline, 0) = Geometry::Deserialize(arena, geom_blob);
return Geometry::Serialize(mline, result);
}
case GeometryType::POLYGON: {
auto mpoly = MultiPolygon::Create(arena, 1, has_z, has_m);
MultiPolygon::Part(mpoly, 0) = Geometry::Deserialize(arena, geom_blob);
return Geometry::Serialize(mpoly, result);
}
default:
return geom_blob;
}
});
}

//------------------------------------------------------------------------------
// Documentation
//------------------------------------------------------------------------------
static constexpr const char *DOC_DESCRIPTION = R"(
Turns a single geometry into a multi geometry.
If the geometry is already a multi geometry, it is returned as is.
)";

static constexpr const char *DOC_EXAMPLE = R"(
SELECT ST_Multi(ST_GeomFromText('POINT(1 2)'));
-- MULTIPOINT (1 2)
SELECT ST_Multi(ST_GeomFromText('LINESTRING(1 1, 2 2)'));
-- MULTILINESTRING ((1 1, 2 2))
SELECT ST_Multi(ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'));
-- MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)))
)";

static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "construction"}};

//------------------------------------------------------------------------------
// Register functions
//------------------------------------------------------------------------------
void CoreScalarFunctions::RegisterStMulti(DatabaseInstance &db) {
ScalarFunction function("ST_Multi",{GeoTypes::GEOMETRY()}, GeoTypes::GEOMETRY(), GeometryMultiFunction);
function.init_local_state = GeometryFunctionLocalState::Init;
ExtensionUtil::RegisterFunction(db, function);
DocUtil::AddDocumentation(db, "ST_Multi", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS);
}

} // namespace core

} // namespace spatial
21 changes: 21 additions & 0 deletions test/sql/geometry/st_multi.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require spatial

query I
SELECT ST_Multi(ST_GeomFromText('POINT(1 2)'));
----
MULTIPOINT (1 2)

query I
SELECT ST_Multi(ST_GeomFromText('LINESTRING(1 1, 2 2)'));
----
MULTILINESTRING ((1 1, 2 2))

query I
SELECT ST_Multi(ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'));
----
MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)))

query I
SELECT ST_Multi(ST_GeomFromText('POINT EMPTY'));
----
MULTIPOINT (EMPTY)

0 comments on commit 5ec66ad

Please sign in to comment.