Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion duckdb
Submodule duckdb updated 958 files
44 changes: 44 additions & 0 deletions src/spatial/modules/geos/geos_geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "geos_c.h"

#include "duckdb/common/vector.hpp"
#include "duckdb/common/unique_ptr.hpp"

namespace duckdb {

Expand Down Expand Up @@ -96,6 +97,7 @@ class GeosGeometry {
GeosGeometry get_buffer_style(double distance, int quadsegs, int endcap_style, int join_style,
double mitre_limit) const;

GeosGeometry get_coverage_clean(double snapping_distance, double gap_maximum_width) const;
GeosGeometry get_coverage_invalid_edges(double tolerance) const;
GeosGeometry get_coverage_simplified(double tolerance, bool preserve_boundary) const;
GeosGeometry get_coverage_union() const;
Expand Down Expand Up @@ -507,11 +509,53 @@ inline GeosGeometry GeosGeometry::get_buffer_style(double distance, int quadsegs
return GeosGeometry(handle, buffer);
}

inline GeosGeometry GeosGeometry::get_coverage_clean(double snapping_distance, double gap_maximum_width) const {

auto *params_raw = GEOSCoverageCleanParams_create_r(handle);
if (!params_raw) {
// Failed to allocate params; return an empty/invalid geometry handle
return GeosGeometry(handle, nullptr);
}

// ensure params tidy themselves up after use
struct ParamsDeleter {
GEOSContextHandle_t h;
void operator()(GEOSCoverageCleanParams *p) const {
if (p) {
GEOSCoverageCleanParams_destroy_r(h, p);
}
}
};

unique_ptr<GEOSCoverageCleanParams, ParamsDeleter> params(params_raw, ParamsDeleter{handle});

// Conditionally set optional parameters; check return codes and fail fast
if (snapping_distance >= 0) {
if (!GEOSCoverageCleanParams_setSnappingDistance_r(handle, params.get(), snapping_distance)) {
return GeosGeometry(handle, nullptr);
}
}
if (gap_maximum_width >= 0) {
if (!GEOSCoverageCleanParams_setGapMaximumWidth_r(handle, params.get(), gap_maximum_width)) {
return GeosGeometry(handle, nullptr);
}
}

// Overlap merge strategy: using a literal to avoid a dependency on enum values when I don't know the wider impact
// 0 is MERGE_LONGEST_BORDER
if (!GEOSCoverageCleanParams_setOverlapMergeStrategy_r(handle, params.get(), 0)) {
return GeosGeometry(handle, nullptr);
}

return GeosGeometry(handle, GEOSCoverageCleanWithParams_r(handle, geom, params.get()));
}

inline GeosGeometry GeosGeometry::get_coverage_invalid_edges(double tolerance) const {
GEOSGeometry *output = nullptr;
GEOSCoverageIsValid_r(handle, geom, tolerance, &output);
return GeosGeometry(handle, output);
}

inline GeosGeometry GeosGeometry::get_coverage_simplified(double tolerance, bool preserve_boundary) const {
return GeosGeometry(handle, GEOSCoverageSimplifyVW_r(handle, geom, tolerance, preserve_boundary));
}
Expand Down
105 changes: 105 additions & 0 deletions src/spatial/modules/geos/geos_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,110 @@ struct ST_ConvexHull {
}
};

struct ST_CoverageClean {

static unique_ptr<FunctionData> Bind(ClientContext &context, ScalarFunction &bound_function,
vector<unique_ptr<Expression>> &arguments) {
// set default values for coverage_clean parameters
const size_t num_args = arguments.size();
if (num_args == 2) { // gap max width
arguments.push_back(make_uniq_base<Expression, BoundConstantExpression>(Value::DOUBLE(-1)));
}

if (num_args == 1) { // snapping distance, gap max width
arguments.push_back(make_uniq_base<Expression, BoundConstantExpression>(Value::DOUBLE(-1)));
arguments.push_back(make_uniq_base<Expression, BoundConstantExpression>(Value::DOUBLE(-1)));
}

return nullptr;
}

static void Execute(DataChunk &args, ExpressionState &state, Vector &result) {
auto &lstate = LocalState::ResetAndGet(state);
UnifiedVectorFormat format;

auto &list_vec = args.data[0];
auto &item_vec = ListVector::GetEntry(list_vec);
item_vec.ToUnifiedFormat(ListVector::GetListSize(list_vec), format);

// Collection to hold the working set of geometries
GeosCollection collection(lstate.GetContext());

TernaryExecutor::Execute<list_entry_t, double, double, string_t>(
list_vec, args.data[1], args.data[2],
result, args.size(), [&](const list_entry_t &list,
double snapping_distance, double gap_maximum_width) {
// Reset the collection
collection.clear();
collection.reserve(list.length);

const auto offset = list.offset;
const auto length = list.length;

// Collect all geometries in the list into the collection
for (idx_t i = offset; i < offset + length; i++) {
const auto mapped_idx = format.sel->get_index(i);

if (!format.validity.RowIsValid(mapped_idx)) {
continue;
}

const auto &geom_blob = UnifiedVectorFormat::GetData<string_t>(format)[mapped_idx];

auto geom = lstate.Deserialize(geom_blob);
collection.add(std::move(geom));
}

// Now make a geometrycollection and simplify
const auto geometry_col = collection.get_collection();
const auto cleaned = geometry_col.get_coverage_clean(snapping_distance, gap_maximum_width);
return lstate.Serialize(result, cleaned);
});
}

static void Register(ExtensionLoader &loader) {
FunctionBuilder::RegisterScalar(loader, "ST_CoverageClean", [](ScalarFunctionBuilder &func) {
func.AddVariant([](ScalarFunctionVariantBuilder &variant) {
variant.AddParameter("geoms", LogicalType::LIST(LogicalType::GEOMETRY()));
variant.AddParameter("snapping_distance", LogicalType::DOUBLE);
variant.AddParameter("gap_maximum_width", LogicalType::DOUBLE);
variant.SetReturnType(LogicalType::GEOMETRY());

variant.SetInit(LocalState::Init);
variant.SetBind(Bind);
variant.SetFunction(Execute);
});

func.AddVariant([](ScalarFunctionVariantBuilder &variant) {
variant.AddParameter("geoms", LogicalType::LIST(LogicalType::GEOMETRY()));
variant.AddParameter("snapping_distance", LogicalType::DOUBLE);
variant.SetReturnType(LogicalType::GEOMETRY());

variant.SetInit(LocalState::Init);
variant.SetBind(Bind);
variant.SetFunction(Execute);
});

func.AddVariant([](ScalarFunctionVariantBuilder &variant) {
variant.AddParameter("geoms", LogicalType::LIST(LogicalType::GEOMETRY()));
variant.SetReturnType(LogicalType::GEOMETRY());

variant.SetInit(LocalState::Init);
variant.SetBind(Bind);
variant.SetFunction(Execute);
});

func.SetDescription(R"(
Aligns the edges of a list of polygons whose edges are meant to align but are in fact exact matches.

Returns a collection of fixed polygons with the same size and order as the input polygons. EMPTY will be used in place of collapsed polygons.
)");
func.SetTag("ext", "spatial");
func.SetTag("category", "construction");
});
}
};

struct ST_CoverageInvalidEdges {

static unique_ptr<FunctionData> Bind(ClientContext &context, ScalarFunction &bound_function,
Expand Down Expand Up @@ -3195,6 +3299,7 @@ void RegisterGEOSModule(ExtensionLoader &loader) {
ST_WithinProperly::Register(loader);
ST_ConcaveHull::Register(loader);
ST_ConvexHull::Register(loader);
ST_CoverageClean::Register(loader);
ST_CoverageInvalidEdges::Register(loader);
ST_CoverageSimplify::Register(loader);
ST_CoverageUnion::Register(loader);
Expand Down
18 changes: 18 additions & 0 deletions test/sql/geos/st_coverageclean.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require spatial

# As per st_isvalid, we trust that GEOS knows what it's doing, so we're not interested in testing this too much

query I
SELECT ST_CoverageClean( [
ST_GeomFromText('POLYGON ((533135.006 124828.779, 533140.387 124828.514, 533142.884 124828.615, 533146.44 124829.532, 533150.1 124830.7, 533152.1 124831.7, 533154.2 124832.85, 533157.35 124834.65, 533160.7 124836.85, 533161.35 124837.3, 533161.75 124837.64, 533170.25 124843.55, 533173.05 124845.5, 533191.4 124860.95, 533195.3 124863.32, 533194.65 124864.55, 533193.95 124870.85, 533193.91 124871.2, 533193 124879.25, 533192.81 124881.72, 533192.5 124885.65, 533191.8 124894.05, 533191.63 124897.53, 533191.51 124899.98, 533191.4 124902.2, 533191.32 124903.77, 533191.01 124910.41, 533190.91 124912.57, 533190.589 124913.407, 533190.69 124913.52, 533191 124913.82, 533191.2 124913.99, 533191.4 124914.15, 533191.61 124914.31, 533191.82 124914.45, 533192.04 124914.58, 533192.27 124914.71, 533209.378 124922.281, 533233.851 124933.109, 533234.178 124933.251, 533241.486 124936.502, 533256.269 124943.011, 533272.689 124950.307, 533280.96 124953.37, 533310.314 124966.309, 533327.77 124974.03, 533328.15 124973.2, 533338.87 124949.39, 533344.25 124937.45, 533345.6 124934.43, 533348.18 124928.68, 533347.38 124928.19, 533347.5 124927.8, 533336.95 124921.25, 533325.54 124916.43, 533325.35 124916.35, 533319.85 124914.1, 533315.09 124912.14, 533313.55 124911.5, 533307.35 124912.45, 533306.12 124912.1, 533296.68 124909.37, 533295.9 124909.15, 533287.2 124904.1, 533288.2 124901.35, 533281.6 124898.6, 533281.501 124898.845, 533275.72 124896.47, 533275.633 124896.434, 533275.55 124896.4, 533266.949 124892.9, 533266.369 124892.709, 533265.48 124894.96, 533260.4 124892.9, 533259.42 124892.46, 533256.7 124891.25, 533254.07 124890.13, 533251.65 124889.1, 533248.06 124887.42, 533247.8 124887.3, 533242.85 124885.2, 533242.71 124885.14, 533237.95 124882.95, 533237.16 124882.57, 533233.65 124880.9, 533232.75 124880.4, 533231.62 124879.71, 533230.05 124878.75, 533226.26 124876.52, 533226.05 124876.4, 533220.8 124873.3, 533219.71 124872.62, 533215.95 124870.25, 533210.1 124866.45, 533205.18 124863.03, 533198.3 124858.25, 533197.65 124857.8, 533197.25 124858.2, 533194.15 124855.8, 533192.8 124854.75, 533189.07 124851.79, 533188.2 124851.1, 533185.49 124848.96, 533182.95 124846.95, 533178.4 124843.6, 533175.18 124841.14, 533173.9 124840.15, 533169.8 124837, 533167 124834.9, 533164.35 124833.05, 533164 124832.85, 533160.85 124830.95, 533160.4 124830.7, 533157.15 124829.05, 533153.2 124827.35, 533151.3 124826.65, 533148.15 124825.65, 533143.05 124823.95, 533136.45 124822.05, 533135.8 124826.4, 533135.302 124827.751, 533135.1 124828.3, 533135.006 124828.779))')
, ST_GeomFromText('POLYGON ((533266.369 124892.709, 533266.949 124892.9, 533275.55 124896.4, 533275.633 124896.434, 533275.79 124896.03, 533281.975 124880.06, 533286.87 124867.42, 533289.215 124860.931, 533290.691 124856.899, 533290.339 124856.77, 533284.4 124854.6, 533281.13 124853.37, 533275.1 124869.5, 533275.02 124869.71, 533273.06 124875.11, 533270.65 124881.75, 533267.5 124890.1, 533266.55 124892.25, 533266.369 124892.709))')
, ST_GeomFromText('POLYGON ((533248.06 124887.42, 533251.65 124889.1, 533254.069 124890.13, 533262.6 124867.3, 533264.05 124863.4, 533269.449 124848.95, 533263.699 124846.76, 533262.29 124850.43, 533258.1 124861.4, 533257.3 124863.5, 533248.06 124887.42))')
, ST_GeomFromText('POLYGON ((533275.72 124896.47, 533281.501 124898.845, 533281.6 124898.6, 533291.699 124873.05, 533292.9 124869.7, 533295.339 124863.19, 533296.85 124859.15, 533291.04 124857.026, 533289.524 124861.032, 533286.87 124867.42, 533275.88 124896.06, 533275.72 124896.47))')
, ST_GeomFromText('POLYGON ((533254.069 124890.13, 533256.699 124891.25, 533259.42 124892.46, 533268.949 124867.6, 533269.699 124865.7, 533273.77 124854.73, 533275.132 124851.104, 533273.4 124850.45, 533269.449 124848.95, 533264.05 124863.4, 533262.6 124867.3, 533254.069 124890.13))')
, ST_GeomFromText('POLYGON ((533273.584 124876.936, 533281.975 124880.06, 533286.87 124867.42, 533290.691 124856.899, 533290.339 124856.77, 533286.214 124855.262, 533284.247 124860.343, 533281.686 124859.392, 533280.28 124858.87, 533279.585 124860.745, 533277.06 124867.56, 533273.584 124876.936))')
, ST_GeomFromText('POLYGON ((533259.42 124892.46, 533260.4 124892.9, 533265.48 124894.96, 533266.55 124892.25, 533267.5 124890.1, 533270.65 124881.75, 533273.06 124875.11, 533275.02 124869.71, 533275.1 124869.5, 533281.13 124853.37, 533275.132 124851.104, 533273.77 124854.73, 533269.699 124865.7, 533268.949 124867.6, 533259.42 124892.46))')
]
, 0.5
);;
----
GEOMETRYCOLLECTION (POLYGON ((533251.65 124889.1, 533248.06 124887.42, 533242.85 124885.2, 533237.95 124882.95, 533237.16 124882.57, 533233.65 124880.9, 533232.75 124880.4, 533231.62 124879.71, 533230.05 124878.75, 533226.26 124876.52, 533220.8 124873.3, 533219.71 124872.62, 533215.95 124870.25, 533210.1 124866.45, 533205.18 124863.03, 533198.3 124858.25, 533197.65 124857.8, 533197.25 124858.2, 533194.15 124855.8, 533192.8 124854.75, 533189.07 124851.79, 533188.2 124851.1, 533185.49 124848.96, 533182.95 124846.95, 533178.4 124843.6, 533175.18 124841.14, 533173.9 124840.15, 533169.8 124837, 533167 124834.9, 533164.35 124833.05, 533160.85 124830.95, 533160.4 124830.7, 533157.15 124829.05, 533153.2 124827.35, 533151.3 124826.65, 533148.15 124825.65, 533143.05 124823.95, 533136.45 124822.05, 533135.8 124826.4, 533135.302 124827.751, 533135.006 124828.779, 533140.387 124828.514, 533142.884 124828.615, 533146.44 124829.532, 533150.1 124830.7, 533152.1 124831.7, 533154.2 124832.85, 533157.35 124834.65, 533160.7 124836.85, 533161.35 124837.3, 533161.75 124837.64, 533170.25 124843.55, 533173.05 124845.5, 533191.4 124860.95, 533195.3 124863.32, 533194.65 124864.55, 533193.95 124870.85, 533193 124879.25, 533192.81 124881.72, 533192.5 124885.65, 533191.8 124894.05, 533191.63 124897.53, 533191.51 124899.98, 533191.4 124902.2, 533191.32 124903.77, 533191.01 124910.41, 533190.91 124912.57, 533190.589 124913.407, 533191 124913.82, 533191.4 124914.15, 533191.82 124914.45, 533192.27 124914.71, 533209.378 124922.281, 533233.851 124933.109, 533241.486 124936.502, 533256.269 124943.011, 533272.689 124950.307, 533280.96 124953.37, 533310.314 124966.309, 533327.77 124974.03, 533328.15 124973.2, 533338.87 124949.39, 533344.25 124937.45, 533345.6 124934.43, 533348.18 124928.68, 533347.38 124928.19, 533336.95 124921.25, 533325.54 124916.43, 533319.85 124914.1, 533315.09 124912.14, 533313.55 124911.5, 533307.35 124912.45, 533306.12 124912.1, 533296.68 124909.37, 533295.9 124909.15, 533287.2 124904.1, 533288.2 124901.35, 533281.6 124898.6, 533275.72 124896.47, 533266.949 124892.9, 533266.369 124892.709, 533265.48 124894.96, 533260.4 124892.9, 533259.42 124892.46, 533256.7 124891.25, 533254.07 124890.13, 533251.65 124889.1)), POLYGON ((533266.949 124892.9, 533275.72 124896.47, 533281.975 124880.06, 533286.87 124867.42, 533289.215 124860.931, 533290.691 124856.899, 533286.214 124855.262, 533284.4 124854.6, 533281.13 124853.37, 533275.1 124869.5, 533273.06 124875.11, 533270.65 124881.75, 533267.5 124890.1, 533266.369 124892.709, 533266.949 124892.9)), POLYGON ((533251.65 124889.1, 533254.07 124890.13, 533262.6 124867.3, 533264.05 124863.4, 533269.449 124848.95, 533263.699 124846.76, 533262.29 124850.43, 533258.1 124861.4, 533257.3 124863.5, 533248.06 124887.42, 533251.65 124889.1)), POLYGON ((533281.6 124898.6, 533291.699 124873.05, 533292.9 124869.7, 533295.339 124863.19, 533296.85 124859.15, 533290.691 124856.899, 533289.215 124860.931, 533286.87 124867.42, 533281.975 124880.06, 533275.72 124896.47, 533281.6 124898.6)), POLYGON ((533256.7 124891.25, 533259.42 124892.46, 533268.949 124867.6, 533269.699 124865.7, 533273.77 124854.73, 533275.132 124851.104, 533273.4 124850.45, 533269.449 124848.95, 533264.05 124863.4, 533262.6 124867.3, 533254.07 124890.13, 533256.7 124891.25)), POLYGON EMPTY, POLYGON ((533260.4 124892.9, 533265.48 124894.96, 533266.369 124892.709, 533267.5 124890.1, 533270.65 124881.75, 533273.06 124875.11, 533275.1 124869.5, 533281.13 124853.37, 533275.132 124851.104, 533273.77 124854.73, 533269.699 124865.7, 533268.949 124867.6, 533259.42 124892.46, 533260.4 124892.9)))
Loading