Skip to content

Commit 2a78b18

Browse files
committed
[GH-2799] Add ST_OffsetCurve function
1 parent 23b8a90 commit 2a78b18

21 files changed

Lines changed: 426 additions & 0 deletions

File tree

common/src/main/java/org/apache/sedona/common/Functions.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import org.locationtech.jts.linearref.LengthIndexedLine;
5555
import org.locationtech.jts.operation.buffer.BufferOp;
5656
import org.locationtech.jts.operation.buffer.BufferParameters;
57+
import org.locationtech.jts.operation.buffer.OffsetCurve;
5758
import org.locationtech.jts.operation.distance.DistanceOp;
5859
import org.locationtech.jts.operation.distance3d.Distance3DOp;
5960
import org.locationtech.jts.operation.linemerge.LineMerger;
@@ -424,6 +425,20 @@ else if (singleParam[0].equalsIgnoreCase(listBufferParameters[5])) {
424425
return bufferParameters;
425426
}
426427

428+
public static Geometry offsetCurve(Geometry geometry, double distance) {
429+
return offsetCurve(geometry, distance, BufferParameters.DEFAULT_QUADRANT_SEGMENTS);
430+
}
431+
432+
public static Geometry offsetCurve(Geometry geometry, double distance, int quadrantSegments) {
433+
if (geometry.isEmpty()) {
434+
return null;
435+
}
436+
BufferParameters bufferParameters = new BufferParameters();
437+
bufferParameters.setQuadrantSegments(quadrantSegments);
438+
OffsetCurve oc = new OffsetCurve(geometry, distance, bufferParameters);
439+
return oc.getCurve();
440+
}
441+
427442
public static int bestSRID(Geometry geometry) throws IllegalArgumentException {
428443
// Shift longitudes if geometry crosses dateline
429444
if (crossesDateLine(geometry)) {

common/src/test/java/org/apache/sedona/common/FunctionsTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4250,6 +4250,52 @@ public void shortestLineSameGeometry() {
42504250
assertEquals(0.0, result.getLength(), 1e-6);
42514251
}
42524252

4253+
@Test
4254+
public void offsetCurvePositiveDistance() throws ParseException {
4255+
// Offset to the left of a horizontal line
4256+
Geometry line = Constructors.geomFromWKT("LINESTRING (0 0, 10 0)", 0);
4257+
Geometry result = Functions.offsetCurve(line, 5.0);
4258+
String actual = Functions.asWKT(result);
4259+
assertEquals("LINESTRING (0 5, 10 5)", actual);
4260+
}
4261+
4262+
@Test
4263+
public void offsetCurveNegativeDistance() throws ParseException {
4264+
// Offset to the right of a horizontal line
4265+
Geometry line = Constructors.geomFromWKT("LINESTRING (0 0, 10 0)", 0);
4266+
Geometry result = Functions.offsetCurve(line, -5.0);
4267+
String actual = Functions.asWKT(result);
4268+
assertEquals("LINESTRING (0 -5, 10 -5)", actual);
4269+
}
4270+
4271+
@Test
4272+
public void offsetCurveZeroDistance() throws ParseException {
4273+
// Zero distance returns a copy of the input
4274+
Geometry line = Constructors.geomFromWKT("LINESTRING (0 0, 10 0)", 0);
4275+
Geometry result = Functions.offsetCurve(line, 0.0);
4276+
String actual = Functions.asWKT(result);
4277+
assertEquals("LINESTRING (0 0, 10 0)", actual);
4278+
}
4279+
4280+
@Test
4281+
public void offsetCurveEmptyGeometry() throws ParseException {
4282+
// Empty geometry returns null
4283+
Geometry empty = Constructors.geomFromWKT("LINESTRING EMPTY", 0);
4284+
Geometry result = Functions.offsetCurve(empty, 5.0);
4285+
assertNull(result);
4286+
}
4287+
4288+
@Test
4289+
public void offsetCurveWithQuadrantSegments() throws ParseException {
4290+
// Test with custom quadrant segments
4291+
Geometry line = Constructors.geomFromWKT("LINESTRING (0 0, 10 0)", 0);
4292+
Geometry result = Functions.offsetCurve(line, 5.0, 4);
4293+
assertNotNull(result);
4294+
// The result should still be a simple offset for a straight line
4295+
String actual = Functions.asWKT(result);
4296+
assertEquals("LINESTRING (0 5, 10 5)", actual);
4297+
}
4298+
42534299
@Test
42544300
public void testZmFlag() throws ParseException {
42554301
int _2D = 0, _3DM = 1, _3DZ = 2, _4D = 3;

docs/api/flink/Geometry-Functions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ These functions compute geometric constructions, or alter geometry size or shape
221221
| [ST_LabelPoint](Geometry-Processing/ST_LabelPoint.md) | Geometry | `ST_LabelPoint` computes and returns a label point for a given polygon or geometry collection. The label point is chosen to be sufficiently far from boundaries of the geometry. For a regular Polygo... | v1.7.1 |
222222
| [ST_MinimumBoundingCircle](Geometry-Processing/ST_MinimumBoundingCircle.md) | Geometry | Returns the smallest circle polygon that contains a geometry. The optional quadrantSegments parameter determines how many segments to use per quadrant and the default number of segments is 48. | v1.5.0 |
223223
| [ST_MinimumBoundingRadius](Geometry-Processing/ST_MinimumBoundingRadius.md) | Struct | Returns a struct containing the center point and radius of the smallest circle that contains a geometry. | v1.5.0 |
224+
| [ST_OffsetCurve](Geometry-Processing/ST_OffsetCurve.md) | Geometry | Returns a line at a given offset distance from a linear geometry. Positive distance offsets to the left, negative to the right. | v1.9.0 |
224225
| [ST_OrientedEnvelope](Geometry-Processing/ST_OrientedEnvelope.md) | Geometry | Returns the minimum-area rotated rectangle enclosing a geometry. The rectangle may be rotated relative to the coordinate axes. Degenerate inputs may result in a Point or LineString being returned. | v1.8.1 |
225226
| [ST_PointOnSurface](Geometry-Processing/ST_PointOnSurface.md) | Geometry | Returns a POINT guaranteed to lie on the surface. | v1.2.1 |
226227
| [ST_Polygonize](Geometry-Processing/ST_Polygonize.md) | Geometry | Generates a GeometryCollection composed of polygons that are formed from the linework of an input GeometryCollection. When the input does not contain any linework that forms a polygon, the function... | v1.6.0 |
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
-->
19+
20+
# ST_OffsetCurve
21+
22+
Introduction: Returns a line at a given offset distance from a linear geometry. If the distance is positive, the offset is on the left side of the input line; if it is negative, it is on the right side. Returns null for empty geometries.
23+
24+
The optional third parameter `quadrantSegments` controls the number of line segments used to approximate a quarter circle at round joins. The default value is 8.
25+
26+
Format: `ST_OffsetCurve(geometry: Geometry, distance: Double, quadrantSegments: Integer)`
27+
28+
Format: `ST_OffsetCurve(geometry: Geometry, distance: Double)`
29+
30+
Return type: `Geometry`
31+
32+
Since: `v1.9.0`
33+
34+
SQL Example
35+
36+
```sql
37+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), 5.0))
38+
```
39+
40+
Output: `LINESTRING (0 5, 10 5)`
41+
42+
```sql
43+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), -5.0))
44+
```
45+
46+
Output: `LINESTRING (0 -5, 10 -5)`
47+
48+
```sql
49+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), 5.0, 4))
50+
```
51+
52+
Output: `LINESTRING (0 5, 10 5)`

docs/api/snowflake/vector-data/Geometry-Functions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ These functions compute geometric constructions, or alter geometry size or shape
214214
| [ST_MaximumInscribedCircle](Geometry-Processing/ST_MaximumInscribedCircle.md) | Finds the largest circle that is contained within a (multi)polygon, or which does not overlap any lines and points. Returns a row with fields: |
215215
| [ST_MinimumBoundingCircle](Geometry-Processing/ST_MinimumBoundingCircle.md) | Returns the smallest circle polygon that contains a geometry. |
216216
| [ST_MinimumBoundingRadius](Geometry-Processing/ST_MinimumBoundingRadius.md) | Returns two columns containing the center point and radius of the smallest circle that contains a geometry. |
217+
| [ST_OffsetCurve](Geometry-Processing/ST_OffsetCurve.md) | Returns a line at a given offset distance from a linear geometry. Positive distance offsets to the left, negative to the right. |
217218
| [ST_OrientedEnvelope](Geometry-Processing/ST_OrientedEnvelope.md) | Returns the minimum-area rotated rectangle enclosing a geometry. The rectangle may be rotated relative to the coordinate axes. Degenerate inputs may result in a Point or LineString being returned. |
218219
| [ST_PointOnSurface](Geometry-Processing/ST_PointOnSurface.md) | Returns a POINT guaranteed to lie on the surface. |
219220
| [ST_Polygonize](Geometry-Processing/ST_Polygonize.md) | Generates a GeometryCollection composed of polygons that are formed from the linework of an input GeometryCollection. When the input does not contain any linework that forms a polygon, the function... |
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
-->
19+
20+
# ST_OffsetCurve
21+
22+
Introduction: Returns a line at a given offset distance from a linear geometry. If the distance is positive, the offset is on the left side of the input line; if it is negative, it is on the right side. Returns null for empty geometries.
23+
24+
The optional third parameter `quadrantSegments` controls the number of line segments used to approximate a quarter circle at round joins. The default value is 8.
25+
26+
Format: `ST_OffsetCurve(geometry: Geometry, distance: Double, quadrantSegments: Integer)`
27+
28+
Format: `ST_OffsetCurve(geometry: Geometry, distance: Double)`
29+
30+
Return type: `Geometry`
31+
32+
SQL Example
33+
34+
```sql
35+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), 5.0))
36+
```
37+
38+
Output: `LINESTRING (0 5, 10 5)`
39+
40+
```sql
41+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), -5.0))
42+
```
43+
44+
Output: `LINESTRING (0 -5, 10 -5)`
45+
46+
```sql
47+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), 5.0, 4))
48+
```
49+
50+
Output: `LINESTRING (0 5, 10 5)`

docs/api/sql/Geometry-Functions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ These functions compute geometric constructions, or alter geometry size or shape
223223
| [ST_MaximumInscribedCircle](Geometry-Processing/ST_MaximumInscribedCircle.md) | Struct | Finds the largest circle that is contained within a (multi)polygon, or which does not overlap any lines and points. Returns a row with fields: | v1.6.1 |
224224
| [ST_MinimumBoundingCircle](Geometry-Processing/ST_MinimumBoundingCircle.md) | Geometry | Returns the smallest circle polygon that contains a geometry. The optional quadrantSegments parameter determines how many segments to use per quadrant and the default number of segments has been ch... | v1.0.1 |
225225
| [ST_MinimumBoundingRadius](Geometry-Processing/ST_MinimumBoundingRadius.md) | Struct | Returns a struct containing the center point and radius of the smallest circle that contains a geometry. | v1.0.1 |
226+
| [ST_OffsetCurve](Geometry-Processing/ST_OffsetCurve.md) | Geometry | Returns a line at a given offset distance from a linear geometry. Positive distance offsets to the left, negative to the right. | v1.9.0 |
226227
| [ST_OrientedEnvelope](Geometry-Processing/ST_OrientedEnvelope.md) | Geometry | Returns the minimum-area rotated rectangle enclosing a geometry. The rectangle may be rotated relative to the coordinate axes. Degenerate inputs may result in a Point or LineString being returned. | v1.8.1 |
227228
| [ST_PointOnSurface](Geometry-Processing/ST_PointOnSurface.md) | Geometry | Returns a POINT guaranteed to lie on the surface. | v1.2.1 |
228229
| [ST_Polygonize](Geometry-Processing/ST_Polygonize.md) | Geometry | Generates a GeometryCollection composed of polygons that are formed from the linework of an input GeometryCollection. When the input does not contain any linework that forms a polygon, the function... | v1.6.0 |
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
-->
19+
20+
# ST_OffsetCurve
21+
22+
![ST_OffsetCurve](../../../image/ST_OffsetCurve/ST_OffsetCurve.svg "ST_OffsetCurve")
23+
24+
Introduction: Returns a line at a given offset distance from a linear geometry. If the distance is positive, the offset is on the left side of the input line; if it is negative, it is on the right side. Returns null for empty geometries.
25+
26+
The optional third parameter `quadrantSegments` controls the number of line segments used to approximate a quarter circle at round joins. The default value is 8.
27+
28+
Format: `ST_OffsetCurve(geometry: Geometry, distance: Double, quadrantSegments: Integer)`
29+
30+
Format: `ST_OffsetCurve(geometry: Geometry, distance: Double)`
31+
32+
Return type: `Geometry`
33+
34+
Since: `v1.9.0`
35+
36+
SQL Example
37+
38+
```sql
39+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), 5.0))
40+
```
41+
42+
Output: `LINESTRING (0 5, 10 5)`
43+
44+
```sql
45+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), -5.0))
46+
```
47+
48+
Output: `LINESTRING (0 -5, 10 -5)`
49+
50+
```sql
51+
SELECT ST_AsText(ST_OffsetCurve(ST_GeomFromWKT('LINESTRING(0 0, 10 0)'), 5.0, 4))
52+
```
53+
54+
Output: `LINESTRING (0 5, 10 5)`
Lines changed: 34 additions & 0 deletions
Loading

flink/src/main/java/org/apache/sedona/flink/Catalog.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public static UserDefinedFunction[] getFuncs() {
7070
new Functions.ST_BestSRID(),
7171
new Functions.ST_ClosestPoint(),
7272
new Functions.ST_ShortestLine(),
73+
new Functions.ST_OffsetCurve(),
7374
new Functions.ST_Centroid(),
7475
new Functions.ST_Collect(),
7576
new Functions.ST_CollectionExtract(),

0 commit comments

Comments
 (0)