Skip to content

Commit

Permalink
Merge pull request #331 from Maxxen/dev-stable
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxxen authored Jun 6, 2024
2 parents 8c588e0 + 28ba343 commit e04e2f0
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 30 deletions.
1 change: 1 addition & 0 deletions deps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ ExternalProject_Add(
-DOGR_ENABLE_DRIVER_MVT=ON
-DOGR_ENABLE_DRIVER_PMTILES=ON
-DOGR_ENABLE_DRIVER_JSONFG=ON
-DOGR_ENABLE_DRIVER_GTFS=ON

# Drivers requiring network/curl
-DOGR_ENABLE_DRIVER_AMIGOCLOUD=${SPATIAL_USE_NETWORK}
Expand Down
38 changes: 34 additions & 4 deletions docs/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
| [ST_Distance](#st_distance) | Returns the distance between two geometries. |
| [ST_Distance_Sphere](#st_distance_sphere) | Returns the haversine distance between two geometries. |
| [ST_Distance_Spheroid](#st_distance_spheroid) | Returns the distance between two geometries in meters using a ellipsoidal model of the earths surface |
| [ST_Dump](#st_dump) | Dumps a geometry into a set of sub-geometries |
| [ST_Dump](#st_dump) | Dumps a geometry into a set of sub-geometries and their "path" in the original geometry. |
| [ST_EndPoint](#st_endpoint) | Returns the end point of a line. |
| [ST_Envelope](#st_envelope) | Returns the minimum bounding box for the input geometry as a polygon geometry. |
| [ST_Equals](#st_equals) | Compares two geometries for equality |
Expand Down Expand Up @@ -82,6 +82,7 @@
| [ST_Point4D](#st_point4d) | Creates a POINT_4D |
| [ST_PointN](#st_pointn) | Returns the n'th vertex from the input geometry as a point geometry |
| [ST_PointOnSurface](#st_pointonsurface) | Returns a point that is guaranteed to be on the surface of the input geometry. Sometimes a useful alternative to ST_Centroid. |
| [ST_Points](#st_points) | Collects all the vertices in the geometry into a multipoint |
| [ST_QuadKey](#st_quadkey) | Computes a quadkey from a given lon/lat point. |
| [ST_ReducePrecision](#st_reduceprecision) | Returns the geometry with all vertices reduced to the target precision |
| [ST_RemoveRepeatedPoints](#st_removerepeatedpoints) | Returns a new geometry with repeated points removed, optionally within a target distance of eachother. |
Expand All @@ -103,13 +104,15 @@
| [ST_Z](#st_z) | Returns the Z value of a point geometry, or NULL if not a point or empty |
| [ST_ZMax](#st_zmax) | Returns the maximum Z value of a geometry |
| [ST_ZMin](#st_zmin) | Returns the minimum Z value of a geometry |

**[Aggregate Functions](#aggregate-functions)**

| Function | Summary |
| --- | --- |
| [ST_Envelope_Agg](#st_envelope_agg) | Computes a minimal-bounding-box polygon 'enveloping' the set of input geometries |
| [ST_Intersection_Agg](#st_intersection_agg) | Computes the intersection of a set of geometries |
| [ST_Union_Agg](#st_union_agg) | Computes the union of a set of input geometries |

**[Table Functions](#table-functions)**

| Function | Summary |
Expand All @@ -118,6 +121,7 @@
| [ST_Read](#st_read) | Read and import a variety of geospatial file formats using the GDAL library. |
| [ST_ReadOSM](#st_readosm) | The ST_ReadOsm() table function enables reading compressed OpenStreetMap data directly from a `.osm.pbf file.` |
| [ST_Read_Meta](#st_read_meta) | Read and the metadata from a variety of geospatial file formats using the GDAL library. |

----

## Scalar Functions
Expand Down Expand Up @@ -704,7 +708,7 @@ st_point(52.3130, 4.7725)

### ST_Dump

_Dumps a geometry into a set of sub-geometries_
_Dumps a geometry into a set of sub-geometries and their "path" in the original geometry._

#### Signature

Expand All @@ -714,8 +718,6 @@ STRUCT(geom GEOMETRY, path INTEGER[])[] ST_Dump (col0 GEOMETRY)

#### Description

Dumps a geometry into a set of sub-geometries

Dumps a geometry into a set of sub-geometries and their "path" in the original geometry.

#### Example
Expand Down Expand Up @@ -1615,6 +1617,34 @@ Returns a point that is guaranteed to be on the surface of the input geometry. S



### ST_Points

_Collects all the vertices in the geometry into a multipoint_

#### Signature

```sql
GEOMETRY ST_Points (col0 GEOMETRY)
```

#### Description

Collects all the vertices in the geometry into a multipoint

#### Example

```sql
select st_points('LINESTRING(1 1, 2 2)'::geometry);
----
MULTIPOINT (1 1, 2 2)

select st_points('MULTIPOLYGON Z EMPTY'::geometry);
----
MULTIPOINT Z EMPTY
```



### ST_QuadKey

_Computes a quadkey from a given lon/lat point._
Expand Down
12 changes: 7 additions & 5 deletions generate_function_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
json({
name: function_name,
signatures: signatures,
tags: tags,
tags: func_tags,
description: description,
example: example
})
Expand All @@ -18,13 +18,13 @@
return: return_type,
params: list_zip(parameters, parameter_types)::STRUCT(name VARCHAR, type VARCHAR)[]
}) as signatures,
any_value(try_cast(comment AS STRUCT(key VARCHAR, value VARCHAR)[])) as tags,
any_value(tags) AS func_tags,
any_value(description) AS description,
any_value(example) AS example
FROM duckdb_functions()
FROM duckdb_functions() as funcs
WHERE function_type = '$FUNCTION_TYPE$'
GROUP BY function_name, function_type
HAVING list_contains(tags, {key: 'ext', value: 'spatial'})
HAVING func_tags['ext'] = ['spatial']
ORDER BY function_name
);
"""
Expand Down Expand Up @@ -62,11 +62,13 @@ def main():
f.write("## Function Index \n")
f.write("**[Scalar Functions](#scalar-functions)**\n\n")
write_table_of_contents(f, scalar_functions)
f.write("\n")
f.write("**[Aggregate Functions](#aggregate-functions)**\n\n")
write_table_of_contents(f, aggregate_functions)
f.write("\n")
f.write("**[Table Functions](#table-functions)**\n\n")
write_table_of_contents(f, table_functions)

f.write("\n")
f.write("----\n\n")

# Write basic functions
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 @@ -45,6 +45,7 @@ struct CoreScalarFunctions {
RegisterStPerimeter(db);
RegisterStPoint(db);
RegisterStPointN(db);
RegisterStPoints(db);
RegisterStQuadKey(db);
RegisterStRemoveRepeatedPoints(db);
RegisterStStartPoint(db);
Expand Down Expand Up @@ -174,6 +175,9 @@ struct CoreScalarFunctions {
// ST_PointN
static void RegisterStPointN(DatabaseInstance &db);

// ST_Points
static void RegisterStPoints(DatabaseInstance &db);

// ST_RemoveRepeatedPoints
static void RegisterStRemoveRepeatedPoints(DatabaseInstance &db);

Expand Down
12 changes: 5 additions & 7 deletions spatial/include/spatial/doc_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,18 @@ struct DocTag {

struct DocUtil {
static void AddDocumentation(duckdb::DatabaseInstance &db, const char *function_name, const char *description,
const char *example, const duckdb::Value &comment);
const char *example,
const duckdb::unordered_map<duckdb::string, duckdb::string> &tags);

// Abuse adding tags as a comment
template <size_t N>
static void AddDocumentation(duckdb::DatabaseInstance &db, const char *function_name, const char *description,
const char *example, const DocTag (&tags)[N]) {
auto kv_type = duckdb::LogicalType::STRUCT(
{{"key", duckdb::LogicalType::VARCHAR}, {"value", duckdb::LogicalType::VARCHAR}});
duckdb::vector<duckdb::Value> tag_values;
duckdb::unordered_map<duckdb::string, duckdb::string> tag_map;
for (size_t i = 0; i < N; i++) {
auto &tag = tags[i];
tag_values.push_back(duckdb::Value::STRUCT(kv_type, {duckdb::Value(tag.key), duckdb::Value(tag.value)}));
tag_map[tags[i].key] = tags[i].value;
}
AddDocumentation(db, function_name, description, example, duckdb::Value::LIST(kv_type, tag_values));
AddDocumentation(db, function_name, description, example, tag_map);
}
};

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 @@ -36,6 +36,7 @@ set(EXTENSION_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/st_perimeter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_point.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_pointn.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_points.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_quadkey.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_removerepeatedpoints.cpp
${CMAKE_CURRENT_SOURCE_DIR}/st_startpoint.cpp
Expand Down
4 changes: 0 additions & 4 deletions spatial/src/spatial/core/functions/scalar/st_dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#include "spatial/core/geometry/geometry.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 {

Expand Down Expand Up @@ -119,8 +117,6 @@ static void DumpFunction(DataChunk &args, ExpressionState &state, Vector &result
// Documentation
//------------------------------------------------------------------------------
static constexpr const char *DOC_DESCRIPTION = R"(
Dumps a geometry into a set of sub-geometries
Dumps a geometry into a set of sub-geometries and their "path" in the original geometry.
)";

Expand Down
110 changes: 110 additions & 0 deletions spatial/src/spatial/core/functions/scalar/st_points.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "spatial/common.hpp"
#include "spatial/core/types.hpp"
#include "spatial/core/functions/scalar.hpp"
#include "spatial/core/functions/common.hpp"
#include "spatial/core/geometry/geometry.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 core {

//------------------------------------------------------------------------------
// GEOMETRY
//------------------------------------------------------------------------------
static void GeometryPointsFunction(DataChunk &args, ExpressionState &state, Vector &result) {

// Collect all vertex data into a buffer
struct op {
static void Case(Geometry::Tags::SinglePartGeometry, const Geometry &geom, vector<const_data_ptr_t> &buffer) {
const auto vertex_count = SinglePartGeometry::VertexCount(geom);
const auto vertex_size = SinglePartGeometry::VertexSize(geom);

// Reserve size for the pointers to the vertices
buffer.reserve(buffer.size() + vertex_count);

const auto vertex_ptr = geom.GetData();

for (uint32_t i = 0; i < vertex_count; i++) {
buffer.push_back(vertex_ptr + i * vertex_size);
}
}
static void Case(Geometry::Tags::MultiPartGeometry, const Geometry &geom, vector<const_data_ptr_t> &buffer) {
for (auto &part : MultiPartGeometry::Parts(geom)) {
Geometry::Match<op>(part, buffer);
}
}
};

auto &lstate = GeometryFunctionLocalState::ResetAndGet(state);
auto &arena = lstate.arena;
auto &geom_vec = args.data[0];
const auto count = args.size();

vector<const_data_ptr_t> vertex_ptr_buffer;

UnaryExecutor::Execute<geometry_t, geometry_t>(geom_vec, result, count, [&](geometry_t input) {
const auto geom = Geometry::Deserialize(arena, input);
const auto has_z = geom.GetProperties().HasZ();
const auto has_m = geom.GetProperties().HasM();

// Reset the vertex pointer buffer
vertex_ptr_buffer.clear();

// Collect the vertex pointers
Geometry::Match<op>(geom, vertex_ptr_buffer);

if (vertex_ptr_buffer.empty()) {
const auto mpoint = MultiPoint::CreateEmpty(has_z, has_m);
return Geometry::Serialize(mpoint, result);
}

auto mpoint = MultiPoint::Create(arena, vertex_ptr_buffer.size(), has_z, has_m);
for (size_t i = 0; i < vertex_ptr_buffer.size(); i++) {
// Get the nth point
auto &point = MultiPoint::Part(mpoint, i);
// Set the point to reference the data pointer to the current vertex
Point::ReferenceData(point, vertex_ptr_buffer[i], 1, has_z, has_m);
}
return Geometry::Serialize(mpoint, result);
});
}

//------------------------------------------------------------------------------
// Documentation
//------------------------------------------------------------------------------
static constexpr const char *DOC_DESCRIPTION = R"(
Collects all the vertices in the geometry into a multipoint
)";

static constexpr const char *DOC_EXAMPLE = R"(
select st_points('LINESTRING(1 1, 2 2)'::geometry);
----
MULTIPOINT (1 1, 2 2)
select st_points('MULTIPOLYGON Z EMPTY'::geometry);
----
MULTIPOINT Z EMPTY
)";

static constexpr DocTag DOC_TAGS[] = {{"ext", "spatial"}, {"category", "construction"}};
//------------------------------------------------------------------------------
// Register functions
//------------------------------------------------------------------------------
void CoreScalarFunctions::RegisterStPoints(DatabaseInstance &db) {

ScalarFunctionSet set("ST_Points");

set.AddFunction(ScalarFunction({GeoTypes::GEOMETRY()}, GeoTypes::GEOMETRY(), GeometryPointsFunction, nullptr,
nullptr, nullptr, GeometryFunctionLocalState::Init));

ExtensionUtil::RegisterFunction(db, set);
DocUtil::AddDocumentation(db, "ST_Points", DOC_DESCRIPTION, DOC_EXAMPLE, DOC_TAGS);
}

} // namespace core

} // namespace spatial
4 changes: 2 additions & 2 deletions spatial/src/spatial/core/io/shapefile/read_shapefile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ struct ShapefileBindData : TableFunctionData {
vector<LogicalType> attribute_types;

explicit ShapefileBindData(string file_name_p)
: file_name(std::move(file_name_p)), shape_count(0),
shape_type(0), min_bound {0, 0, 0, 0}, max_bound {0, 0, 0, 0}, attribute_encoding(AttributeEncoding::LATIN1) {
: file_name(std::move(file_name_p)), shape_count(0), shape_type(0), min_bound {0, 0, 0, 0},
max_bound {0, 0, 0, 0}, attribute_encoding(AttributeEncoding::LATIN1) {
}
};

Expand Down
3 changes: 2 additions & 1 deletion spatial/src/spatial/gdal/functions/st_read_meta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ static unique_ptr<FunctionData> Bind(ClientContext &context, TableFunctionBindIn
auto result = make_uniq<GDALMetadataBindData>();

auto multi_file_reader = MultiFileReader::Create(input.table_function);
result->file_names = multi_file_reader->CreateFileList(context, input.inputs[0], FileGlobOptions::ALLOW_EMPTY)->GetAllFiles();
result->file_names =
multi_file_reader->CreateFileList(context, input.inputs[0], FileGlobOptions::ALLOW_EMPTY)->GetAllFiles();

names.push_back("file_name");
return_types.push_back(LogicalType::VARCHAR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ static void GeodesicLineString2DFunction(DataChunk &args, ExpressionState &state
//------------------------------------------------------------------------------
static double LineLength(const Geometry &line, GeographicLib::PolygonArea &comp) {
comp.Clear();
for(uint32_t i = 0; i < LineString::VertexCount(line); i++) {
auto vert = LineString::GetVertex(line, i);
comp.AddPoint(vert.x, vert.y);
}
for (uint32_t i = 0; i < LineString::VertexCount(line); i++) {
auto vert = LineString::GetVertex(line, i);
comp.AddPoint(vert.x, vert.y);
}
double _area;
double linestring_length;
comp.Compute(false, true, linestring_length, _area);
Expand Down
7 changes: 4 additions & 3 deletions spatial/src/spatial_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ static string RemoveIndentAndTrailingWhitespace(const char *text) {
}

void spatial::DocUtil::AddDocumentation(duckdb::DatabaseInstance &db, const char *function_name,
const char *description, const char *example, const Value &comment) {
const char *description, const char *example,
const duckdb::unordered_map<duckdb::string, duckdb::string> &tags) {

auto &system_catalog = Catalog::GetSystemCatalog(db);
auto data = CatalogTransaction::GetSystemTransaction(db);
Expand All @@ -78,8 +79,8 @@ void spatial::DocUtil::AddDocumentation(duckdb::DatabaseInstance &db, const char
if (example != nullptr) {
func_entry.example = RemoveIndentAndTrailingWhitespace(example);
}
if (!comment.IsNull()) {
func_entry.comment = comment;
if (!tags.empty()) {
func_entry.tags = tags;
}
}

Expand Down

0 comments on commit e04e2f0

Please sign in to comment.