Skip to content

Commit 4a67e45

Browse files
committed
Merge branch 'main' of github.com:zhangfengcdt/sedona-db into gpu
2 parents 42ebc68 + bfb94e9 commit 4a67e45

File tree

5 files changed

+210
-0
lines changed

5 files changed

+210
-0
lines changed

c/sedona-geos/benches/geos-functions.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ fn criterion_benchmark(c: &mut Criterion) {
228228
benchmark::scalar(c, &f, "geos", "st_length", LineString(10));
229229
benchmark::scalar(c, &f, "geos", "st_length", LineString(500));
230230

231+
benchmark::scalar(c, &f, "geos", "st_minimumclearanceline", LineString(10));
232+
benchmark::scalar(c, &f, "geos", "st_minimumclearanceline", LineString(500));
233+
231234
benchmark::scalar(
232235
c,
233236
&f,

c/sedona-geos/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod st_isvalid;
3232
mod st_isvalidreason;
3333
mod st_length;
3434
mod st_makevalid;
35+
mod st_minimumclearance_line;
3536
mod st_perimeter;
3637
mod st_polygonize_agg;
3738
mod st_reverse;

c/sedona-geos/src/register.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::{
3131
st_isvalidreason::st_is_valid_reason_impl,
3232
st_length::st_length_impl,
3333
st_makevalid::st_make_valid_impl,
34+
st_minimumclearance_line::st_minimum_clearance_line_impl,
3435
st_perimeter::st_perimeter_impl,
3536
st_polygonize_agg::st_polygonize_agg_impl,
3637
st_reverse::st_reverse_impl,
@@ -74,6 +75,7 @@ pub fn scalar_kernels() -> Vec<(&'static str, ScalarKernelRef)> {
7475
("st_isvalidreason", st_is_valid_reason_impl()),
7576
("st_length", st_length_impl()),
7677
("st_makevalid", st_make_valid_impl()),
78+
("st_minimumclearanceline", st_minimum_clearance_line_impl()),
7779
("st_overlaps", st_overlaps_impl()),
7880
("st_perimeter", st_perimeter_impl()),
7981
("st_reverse", st_reverse_impl()),
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
use std::sync::Arc;
19+
20+
use arrow_array::builder::BinaryBuilder;
21+
use datafusion_common::{DataFusionError, Result};
22+
use datafusion_expr::ColumnarValue;
23+
use geos::Geom;
24+
use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel};
25+
use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES;
26+
use sedona_schema::{
27+
datatypes::{SedonaType, WKB_GEOMETRY},
28+
matchers::ArgMatcher,
29+
};
30+
31+
use crate::executor::GeosExecutor;
32+
33+
/// ST_MinimumClearanceLine() implementation using the geos crate
34+
pub fn st_minimum_clearance_line_impl() -> ScalarKernelRef {
35+
Arc::new(STMinimumClearanceLine {})
36+
}
37+
38+
#[derive(Debug)]
39+
struct STMinimumClearanceLine {}
40+
41+
impl SedonaScalarKernel for STMinimumClearanceLine {
42+
fn return_type(&self, args: &[SedonaType]) -> Result<Option<SedonaType>> {
43+
let matcher = ArgMatcher::new(vec![ArgMatcher::is_geometry()], WKB_GEOMETRY);
44+
45+
matcher.match_args(args)
46+
}
47+
48+
fn invoke_batch(
49+
&self,
50+
arg_types: &[SedonaType],
51+
args: &[ColumnarValue],
52+
) -> Result<ColumnarValue> {
53+
let executor = GeosExecutor::new(arg_types, args);
54+
let mut builder = BinaryBuilder::with_capacity(
55+
executor.num_iterations(),
56+
WKB_MIN_PROBABLE_BYTES * executor.num_iterations(),
57+
);
58+
59+
executor.execute_wkb_void(|maybe_wkb| {
60+
match maybe_wkb {
61+
Some(wkb) => {
62+
invoke_scalar(&wkb, &mut builder)?;
63+
builder.append_value([]);
64+
}
65+
_ => builder.append_null(),
66+
}
67+
68+
Ok(())
69+
})?;
70+
71+
executor.finish(Arc::new(builder.finish()))
72+
}
73+
}
74+
75+
fn invoke_scalar(geos_geom: &geos::Geometry, writer: &mut impl std::io::Write) -> Result<()> {
76+
let geometry = geos_geom.minimum_clearance_line().map_err(|e| {
77+
DataFusionError::Execution(format!(
78+
"Failed to calculate geometry's minimum clearance line: {e}"
79+
))
80+
})?;
81+
82+
let wkb = geometry
83+
.to_wkb()
84+
.map_err(|e| DataFusionError::Execution(format!("Failed to convert to wkb: {e}")))?;
85+
86+
writer.write_all(wkb.as_ref())?;
87+
Ok(())
88+
}
89+
90+
#[cfg(test)]
91+
mod tests {
92+
use rstest::rstest;
93+
use sedona_expr::scalar_udf::SedonaScalarUDF;
94+
use sedona_schema::datatypes::WKB_VIEW_GEOMETRY;
95+
use sedona_testing::{create::create_array, testers::ScalarUdfTester};
96+
97+
use super::*;
98+
99+
#[rstest]
100+
fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) {
101+
let udf = SedonaScalarUDF::from_kernel(
102+
"st_minimumclearanceline",
103+
st_minimum_clearance_line_impl(),
104+
);
105+
let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type.clone()]);
106+
tester.assert_return_type(WKB_GEOMETRY);
107+
108+
let input_wkt = vec![
109+
None,
110+
Some("POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))"),
111+
Some("MULTIPOLYGON(((26 125, 26 200, 126 200, 126 125, 26 125 ),( 51 150, 101 150, 76 175, 51 150 )),(( 151 100, 151 200, 176 175, 151 100 )))"),
112+
Some("LINESTRING (5 107, 54 84, 101 100)"),
113+
Some("POLYGON((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))"),
114+
Some("POLYGON((0 0,0 1,0 1,1 1,1 0,0 0,0 0))"),
115+
Some("LINESTRING (0 0, 1 1, 2 2)"),
116+
Some("MULTIPOLYGON(((0.5 0.5,0 0,0 1,0.5 0.5)),((0.5 0.5,1 1,1 0,0.5 0.5)),((2.5 2.5,2 2,2 3,2.5 2.5)),((2.5 2.5,3 3,3 2,2.5 2.5)))"),
117+
Some("POINT (1 1)"),
118+
Some("GEOMETRYCOLLECTION(POINT(1 1),MULTIPOLYGON(((0 2,1 1,0 0,0 2)),((2 0,1 1,2 2,2 0))))"),
119+
Some("POLYGON EMPTY"),
120+
Some("POLYGON((0 0,3 0,3 3,2 1,1 3,0 3,0 0))"),
121+
];
122+
let expected = create_array(
123+
&[
124+
None,
125+
Some("LINESTRING(0.5 0.00032,0.5 0)"),
126+
Some("LINESTRING(76 175,76 150)"),
127+
Some("LINESTRING(54 84,101 100)"),
128+
Some("LINESTRING(1 1,1 2)"),
129+
Some("LINESTRING(0 0,0 1)"),
130+
Some("LINESTRING(0 0,1 1)"),
131+
Some("LINESTRING(2.5 2.5,3 2.5)"),
132+
Some("LINESTRING EMPTY"),
133+
Some("LINESTRING(1 1,2 1)"),
134+
Some("LINESTRING EMPTY"),
135+
Some("LINESTRING(1 3,0 3)"),
136+
],
137+
&WKB_GEOMETRY,
138+
);
139+
140+
assert_eq!(&tester.invoke_wkb_array(input_wkt).unwrap(), &expected);
141+
}
142+
}

python/sedonadb/tests/functions/test_functions.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,68 @@ def test_st_makevalid(eng, geom, expected):
20922092
)
20932093

20942094

2095+
@pytest.mark.parametrize("eng", [SedonaDB, PostGIS])
2096+
@pytest.mark.parametrize(
2097+
("geom", "expected"),
2098+
[
2099+
(
2100+
None,
2101+
None,
2102+
),
2103+
(
2104+
"POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))",
2105+
"LINESTRING (0.5 0.00032, 0.5 0)",
2106+
),
2107+
(
2108+
"MULTIPOLYGON(((26 125, 26 200, 126 200, 126 125, 26 125 ),( 51 150, 101 150, 76 175, 51 150 )),(( 151 100, 151 200, 176 175, 151 100 )))",
2109+
"LINESTRING (76 175, 76 150)",
2110+
),
2111+
(
2112+
"LINESTRING (5 107, 54 84, 101 100)",
2113+
"LINESTRING (54 84, 101 100)",
2114+
),
2115+
(
2116+
"POLYGON((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))",
2117+
"LINESTRING (1 1, 1 2)",
2118+
),
2119+
(
2120+
"POLYGON((0 0,0 1,0 1,1 1,1 0,0 0,0 0))",
2121+
"LINESTRING (0 0, 0 1)",
2122+
),
2123+
(
2124+
"LINESTRING (0 0, 1 1, 2 2)",
2125+
"LINESTRING (0 0, 1 1)",
2126+
),
2127+
(
2128+
"MULTIPOLYGON(((0.5 0.5,0 0,0 1,0.5 0.5)),((0.5 0.5,1 1,1 0,0.5 0.5)),((2.5 2.5,2 2,2 3,2.5 2.5)),((2.5 2.5,3 3,3 2,2.5 2.5)))",
2129+
"LINESTRING (2.5 2.5, 3 2.5)",
2130+
),
2131+
(
2132+
"POINT (1 1)",
2133+
"LINESTRING EMPTY",
2134+
),
2135+
(
2136+
"GEOMETRYCOLLECTION(POINT(1 1),MULTIPOLYGON(((0 2,1 1,0 0,0 2)),((2 0,1 1,2 2,2 0))))",
2137+
"LINESTRING (1 1, 2 1)",
2138+
),
2139+
(
2140+
"POLYGON EMPTY",
2141+
"LINESTRING EMPTY",
2142+
),
2143+
(
2144+
"POLYGON((0 0,3 0,3 3,2 1,1 3,0 3,0 0))",
2145+
"LINESTRING (1 3, 0 3)",
2146+
),
2147+
],
2148+
)
2149+
def test_st_minimum_clearance_line(eng, geom, expected):
2150+
eng = eng.create_or_skip()
2151+
eng.assert_query_result(
2152+
f"SELECT ST_MinimumClearanceLine({geom_or_null(geom)})",
2153+
expected,
2154+
)
2155+
2156+
20952157
@pytest.mark.parametrize("eng", [SedonaDB, PostGIS])
20962158
@pytest.mark.parametrize(
20972159
("geom", "expected"),

0 commit comments

Comments
 (0)