You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sedona.apache.org by ji...@apache.org on 2022/10/09 06:56:50 UTC

[incubator-sedona] branch master updated: [SEDONA-171] Add ST_SetPoint to Apache Sedona (#694)

This is an automated email from the ASF dual-hosted git repository.

jiayu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-sedona.git


The following commit(s) were added to refs/heads/master by this push:
     new 206936a0 [SEDONA-171] Add ST_SetPoint to Apache Sedona (#694)
206936a0 is described below

commit 206936a04fe9fdb153bab71ad330e062711421ab
Author: Kengo Seki <se...@apache.org>
AuthorDate: Sun Oct 9 15:56:43 2022 +0900

    [SEDONA-171] Add ST_SetPoint to Apache Sedona (#694)
---
 .../java/org/apache/sedona/common/Functions.java   | 15 +++++++++
 docs/api/flink/Function.md                         | 24 ++++++++++++++
 docs/api/sql/Function.md                           | 24 ++++++++++++++
 .../main/java/org/apache/sedona/flink/Catalog.java |  1 +
 .../apache/sedona/flink/expressions/Functions.java | 10 ++++++
 .../java/org/apache/sedona/flink/FunctionTest.java | 14 ++++++--
 python/sedona/sql/st_functions.py                  | 17 ++++++++++
 python/tests/sql/test_dataframe_api.py             |  4 +++
 .../scala/org/apache/sedona/sql/UDF/Catalog.scala  |  1 +
 .../sql/sedona_sql/expressions/Functions.scala     |  8 +++++
 .../expressions/NullSafeExpressions.scala          | 37 ++++++++++++++++++++++
 .../sql/sedona_sql/expressions/st_functions.scala  |  3 ++
 .../apache/sedona/sql/dataFrameAPITestScala.scala  |  8 +++++
 .../org/apache/sedona/sql/functionTestScala.scala  | 27 ++++++++++++++++
 14 files changed, 190 insertions(+), 3 deletions(-)

diff --git a/common/src/main/java/org/apache/sedona/common/Functions.java b/common/src/main/java/org/apache/sedona/common/Functions.java
index b8c712fe..aeb8abbc 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -335,6 +335,21 @@ public class Functions {
         return null;
     }
 
+    public static Geometry setPoint(Geometry linestring, int position, Geometry point) {
+        if (linestring instanceof LineString) {
+            List<Coordinate> coordinates = new ArrayList<>(Arrays.asList(linestring.getCoordinates()));
+            if (-coordinates.size() <= position && position < coordinates.size()) {
+                if (position < 0) {
+                    coordinates.set(coordinates.size() + position, point.getCoordinate());
+                } else {
+                    coordinates.set(position, point.getCoordinate());
+                }
+                return GEOMETRY_FACTORY.createLineString(coordinates.toArray(new Coordinate[0]));
+            }
+        }
+        return null;
+    }
+
     public static Geometry lineFromMultiPoint(Geometry geometry) {
         if(!(geometry instanceof MultiPoint)) {
             return null;
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index c908a2f3..308a0556 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -636,6 +636,30 @@ SELECT ST_RemovePoint(ST_GeomFromText("LINESTRING(0 0, 1 1, 1 0)"), 1)
 
 Output: `LINESTRING(0 0, 1 0)`
 
+## ST_SetPoint
+
+Introduction: Replace Nth point of linestring with given point. Index is 0-based. Negative index are counted backwards, e.g., -1 is last point.
+
+Format: `ST_SetPoint (linestring: geometry, index: integer, point: geometry)`
+
+Since: `v1.3.0`
+
+Example:
+
+```SQL
+SELECT ST_SetPoint(ST_GeomFromText('LINESTRING (0 0, 0 1, 1 1)'), 2, ST_GeomFromText('POINT (1 0)')) AS geom
+```
+
+Result:
+
+```
++--------------------------------+
+|                           geom |
++--------------------------------+
+|     LINESTRING (0 0, 0 1, 1 0) |
++--------------------------------+
+```
+
 ## ST_SetSRID
 
 Introduction: Sets the spatial refence system identifier (SRID) of the geometry.
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index 1baacdcd..6a55b969 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -1063,6 +1063,30 @@ Result:
 +---------------------------------------------------------------+
 ```
 
+## ST_SetPoint
+
+Introduction: Replace Nth point of linestring with given point. Index is 0-based. Negative index are counted backwards, e.g., -1 is last point.
+
+Format: `ST_SetPoint (linestring: geometry, index: integer, point: geometry)`
+
+Since: `v1.3.0`
+
+Example:
+
+```SQL
+SELECT ST_SetPoint(ST_GeomFromText('LINESTRING (0 0, 0 1, 1 1)'), 2, ST_GeomFromText('POINT (1 0)')) AS geom
+```
+
+Result:
+
+```
++--------------------------+
+|geom                      |
++--------------------------+
+|LINESTRING (0 0, 0 1, 1 0)|
++--------------------------+
+```
+
 ## ST_SetSRID
 
 Introduction: Sets the spatial refence system identifier (SRID) of the geometry.
diff --git a/flink/src/main/java/org/apache/sedona/flink/Catalog.java b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
index a6a20a27..289cfe38 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -80,6 +80,7 @@ public class Catalog {
                 new Functions.ST_Normalize(),
                 new Functions.ST_AddPoint(),
                 new Functions.ST_RemovePoint(),
+                new Functions.ST_SetPoint(),
                 new Functions.ST_LineFromMultiPoint(),
         };
     }
diff --git a/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java b/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
index de364772..1232f3cc 100644
--- a/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
+++ b/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
@@ -414,6 +414,16 @@ public class Functions {
         }
     }
 
+    public static class ST_SetPoint extends ScalarFunction {
+        @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
+        public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o1, int position,
+                             @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o2) {
+            Geometry linestring = (Geometry) o1;
+            Geometry point = (Geometry) o2;
+            return org.apache.sedona.common.Functions.setPoint(linestring, position, point);
+        }
+    }
+
     public static class ST_LineFromMultiPoint extends ScalarFunction {
         @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
         public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o) {
diff --git a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
index ba205ff9..1afeb47d 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -435,28 +435,36 @@ public class FunctionTest extends TestBase{
     public void testAddPoint() {
         Table pointTable = tableEnv.sqlQuery("SELECT ST_AddPoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1)'), ST_GeomFromWKT('POINT (2 2)'))");
         assertEquals("LINESTRING (0 0, 1 1, 2 2)", first(pointTable).getField(0).toString());
-
     }
 
     @Test
     public void testAddPointWithIndex() {
         Table pointTable = tableEnv.sqlQuery("SELECT ST_AddPoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1)'), ST_GeomFromWKT('POINT (2 2)'), 1)");
         assertEquals("LINESTRING (0 0, 2 2, 1 1)", first(pointTable).getField(0).toString());
-
     }
 
     @Test
     public void testRemovePoint() {
         Table pointTable = tableEnv.sqlQuery("SELECT ST_RemovePoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1, 2 2)'))");
         assertEquals("LINESTRING (0 0, 1 1)", first(pointTable).getField(0).toString());
-
     }
 
     @Test
     public void testRemovePointWithIndex() {
         Table pointTable = tableEnv.sqlQuery("SELECT ST_RemovePoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1, 2 2)'), 1)");
         assertEquals("LINESTRING (0 0, 2 2)", first(pointTable).getField(0).toString());
+    }
 
+    @Test
+    public void testSetPoint() {
+        Table pointTable = tableEnv.sqlQuery("SELECT ST_SetPoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1, 2 2)'), 0, ST_GeomFromWKT('POINT (3 3)'))");
+        assertEquals("LINESTRING (3 3, 1 1, 2 2)", first(pointTable).getField(0).toString());
+    }
+
+    @Test
+    public void testSetPointWithNegativeIndex() {
+        Table pointTable = tableEnv.sqlQuery("SELECT ST_SetPoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1, 2 2)'), -1, ST_GeomFromWKT('POINT (3 3)'))");
+        assertEquals("LINESTRING (0 0, 1 1, 3 3)", first(pointTable).getField(0).toString());
     }
 
     @Test
diff --git a/python/sedona/sql/st_functions.py b/python/sedona/sql/st_functions.py
index ed611efd..d8bbfbcb 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -63,6 +63,7 @@ __all__ = [
     "ST_PrecisionReduce",
     "ST_RemovePoint",
     "ST_Reverse",
+    "ST_SetPoint",
     "ST_SetSRID",
     "ST_SRID",
     "ST_StartPoint",
@@ -827,6 +828,22 @@ def ST_Reverse(geometry: ColumnOrName) -> Column:
     return _call_st_function("ST_Reverse", geometry)
 
 
+@validate_argument_types
+def ST_SetPoint(line_string: ColumnOrName, index: Union[ColumnOrName, int], point: ColumnOrName) -> Column:
+    """Replace a point in a linestring.
+
+    :param line_string: Linestring geometry column which contains the point to be replaced.
+    :type line_string: ColumnOrName
+    :param index: Index for the point to be replaced, 0-based, negative values start from the end so -1 is the last point.
+    :type index: Union[ColumnOrName, int]
+    :param point: Point geometry column to be newly set.
+    :type point: ColumnOrName
+    :return: Linestring geometry column with the replaced point, or null if the index is out of bounds.
+    :rtype: Column
+    """
+    return _call_st_function("ST_SetPoint", (line_string, index, point))
+
+
 @validate_argument_types
 def ST_SetSRID(geometry: ColumnOrName, srid: Union[ColumnOrName, int]) -> Column:
     """Set the SRID for geometry.
diff --git a/python/tests/sql/test_dataframe_api.py b/python/tests/sql/test_dataframe_api.py
index 2b91b636..e072e3e2 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -91,6 +91,7 @@ test_configurations = [
     (stf.ST_PrecisionReduce, ("geom", 1), "precision_reduce_point", "", "POINT (0.1 0.2)"),
     (stf.ST_RemovePoint, ("line", 1), "linestring_geom", "", "LINESTRING (0 0, 2 0, 3 0, 4 0, 5 0)"),
     (stf.ST_Reverse, ("line",), "linestring_geom", "", "LINESTRING (5 0, 4 0, 3 0, 2 0, 1 0, 0 0)"),
+    (stf.ST_SetPoint, ("line", 1, lambda: f.expr("ST_Point(1.0, 1.0)")), "linestring_geom", "", "LINESTRING (0 0, 1 1, 2 0, 3 0, 4 0, 5 0)"),
     (stf.ST_SetSRID, ("point", 3021), "point_geom", "ST_SRID(geom)", 3021),
     (stf.ST_SimplifyPreserveTopology, ("geom", 0.2), "0.9_poly", "", "POLYGON ((0 0, 1 0, 1 1, 0 0))"),
     (stf.ST_SRID, ("point",), "point_geom", "", 0),
@@ -226,6 +227,9 @@ wrong_type_configurations = [
     (stf.ST_RemovePoint, ("", None)),
     (stf.ST_RemovePoint, ("", 1.0)),
     (stf.ST_Reverse, (None,)),
+    (stf.ST_SetPoint, (None, 1, "")),
+    (stf.ST_SetPoint, ("", None, "")),
+    (stf.ST_SetPoint, ("", 1, None)),
     (stf.ST_SetSRID, (None, 3021)),
     (stf.ST_SetSRID, ("", None)),
     (stf.ST_SetSRID, ("", 3021.0)),
diff --git a/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala b/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
index ebfe78dc..2f5280e6 100644
--- a/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
+++ b/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
@@ -97,6 +97,7 @@ object Catalog {
     ST_NumInteriorRings,
     ST_AddPoint,
     ST_RemovePoint,
+    ST_SetPoint,
     ST_IsRing,
     ST_FlipCoordinates,
     ST_LineSubstring,
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
index 658d644e..065539e0 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
@@ -892,6 +892,14 @@ case class ST_RemovePoint(inputExpressions: Seq[Expression])
   }
 }
 
+case class ST_SetPoint(inputExpressions: Seq[Expression])
+  extends InferredTernaryExpression(Functions.setPoint) {
+
+  protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
+    copy(inputExpressions = newChildren)
+  }
+}
+
 case class ST_IsRing(inputExpressions: Seq[Expression])
   extends UnaryGeometryExpression with CodegenFallback {
   assert(inputExpressions.length == 1)
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/NullSafeExpressions.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/NullSafeExpressions.scala
index 8b2b1496..bb0c599a 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/NullSafeExpressions.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/NullSafeExpressions.scala
@@ -209,3 +209,40 @@ abstract class InferredBinaryExpression[A1: InferrableType, A2: InferrableType,
     }
   }
 }
+
+abstract class InferredTernaryExpression[A1: InferrableType, A2: InferrableType, A3: InferrableType, R: InferrableType]
+(f: (A1, A2, A3) => R)
+(implicit val a1Tag: TypeTag[A1], implicit val a2Tag: TypeTag[A2], implicit val a3Tag: TypeTag[A3], implicit val rTag: TypeTag[R])
+  extends Expression with ImplicitCastInputTypes with CodegenFallback with Serializable {
+  import InferredTypes._
+
+  def inputExpressions: Seq[Expression]
+  assert(inputExpressions.length == 3)
+
+  override def children: Seq[Expression] = inputExpressions
+
+  override def toString: String = s" **${getClass.getName}**  "
+
+  override def inputTypes: Seq[AbstractDataType] = Seq(inferSparkType[A1], inferSparkType[A2], inferSparkType[A3])
+
+  override def nullable: Boolean = true
+
+  override def dataType = inferSparkType[R]
+
+  lazy val extractFirst = buildExtractor[A1](inputExpressions(0))
+  lazy val extractSecond = buildExtractor[A2](inputExpressions(1))
+  lazy val extractThird = buildExtractor[A3](inputExpressions(2))
+
+  lazy val serialize = buildSerializer[R]
+
+  override def eval(input: InternalRow): Any = {
+    val first = extractFirst(input)
+    val second = extractSecond(input)
+    val third = extractThird(input)
+    if (first != null && second != null && third != null) {
+      serialize(f(first, second, third))
+    } else {
+      null
+    }
+  }
+}
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
index f0562e38..4a54719f 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
@@ -202,6 +202,9 @@ object st_functions extends DataFrameAPI {
   def ST_Reverse(geometry: Column): Column = wrapExpression[ST_Reverse](geometry)
   def ST_Reverse(geometry: String): Column = wrapExpression[ST_Reverse](geometry)
 
+  def ST_SetPoint(lineString: Column, index: Column, point: Column): Column = wrapExpression[ST_SetPoint](lineString, index, point)
+  def ST_SetPoint(lineString: String, index: Int, point: String): Column = wrapExpression[ST_SetPoint](lineString, index, point)
+
   def ST_SetSRID(geometry: Column, srid: Column): Column = wrapExpression[ST_SetSRID](geometry, srid)
   def ST_SetSRID(geometry: String, srid: Int): Column = wrapExpression[ST_SetSRID](geometry, srid)
 
diff --git a/sql/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala b/sql/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
index 36c805f7..ce7aa0af 100644
--- a/sql/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
+++ b/sql/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
@@ -529,6 +529,14 @@ class dataFrameAPITestScala extends TestBaseScala {
       assert(actualResult == expectedResult)
     }
 
+    it("Passed ST_SetPoint") {
+      val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING (0 0, 1 0)') AS line, ST_Point(1.0, 1.0) AS point")
+      val df = baseDf.select(ST_SetPoint("line", 1, "point"))
+      val actualResult = df.take(1)(0).get(0).asInstanceOf[Geometry].toText()
+      val expectedResult = "LINESTRING (0 0, 1 1)"
+      assert(actualResult == expectedResult)
+    }
+
     it("Passed ST_IsRing") {
       val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING (0 0, 1 0, 1 1, 0 0)') AS geom")
       val df = baseDf.select(ST_IsRing("geom"))
diff --git a/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala b/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
index dee0b983..f642f34c 100644
--- a/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
+++ b/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
@@ -993,6 +993,24 @@ class functionTestScala extends TestBaseScala with Matchers with GeometrySample
     calculateStRemovePointOption("MULTILINESTRING ((10 10, 20 20, 10 40, 10 10), (40 40, 30 30, 40 20, 30 10, 40 40))", 3) shouldBe None
   }
 
+  it("Should correctly set using ST_SetPoint") {
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", 0, "Point(0 1)") shouldBe Some("LINESTRING (0 1, 1 1, 1 0, 0 0)")
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", 1, "Point(0 1)") shouldBe Some("LINESTRING (0 0, 0 1, 1 0, 0 0)")
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", 2, "Point(0 1)") shouldBe Some("LINESTRING (0 0, 1 1, 0 1, 0 0)")
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", 3, "Point(0 1)") shouldBe Some("LINESTRING (0 0, 1 1, 1 0, 0 1)")
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", 4, "Point(0 1)") shouldBe None
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", -1, "Point(0 1)") shouldBe Some("LINESTRING (0 0, 1 1, 1 0, 0 1)")
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", -2, "Point(0 1)") shouldBe Some("LINESTRING (0 0, 1 1, 0 1, 0 0)")
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", -3, "Point(0 1)") shouldBe Some("LINESTRING (0 0, 0 1, 1 0, 0 0)")
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", -4, "Point(0 1)") shouldBe Some("LINESTRING (0 1, 1 1, 1 0, 0 0)")
+    calculateStSetPointOption("Linestring(0 0, 1 1, 1 0, 0 0)", -5, "Point(0 1)") shouldBe None
+    calculateStSetPointOption("POINT(0 1)", 0, "Point(0 1)") shouldBe None
+    calculateStSetPointOption("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0), (1 1, 2 1, 2 2, 1 2, 1 1))", 0, "Point(0 1)") shouldBe None
+    calculateStSetPointOption("GEOMETRYCOLLECTION (POINT (40 10), LINESTRING (10 10, 20 20, 10 40))", 0, "Point(0 1)") shouldBe None
+    calculateStSetPointOption("MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))", 0, "Point(0 1)") shouldBe None
+    calculateStSetPointOption("MULTILINESTRING ((10 10, 20 20, 10 40, 10 10), (40 40, 30 30, 40 20, 30 10, 40 40))", 0, "Point(0 1)") shouldBe None
+  }
+
   it("Should pass ST_IsRing") {
     calculateStIsRing("LINESTRING(0 0, 0 1, 1 0, 1 1, 0 0)") shouldBe Some(false)
     calculateStIsRing("LINESTRING(2 0, 2 2, 3 3)") shouldBe Some(false)
@@ -1152,6 +1170,15 @@ class functionTestScala extends TestBaseScala with Matchers with GeometrySample
       .filter("geom is not null")
       .selectExpr("ST_AsText(geom)").as[String].collect()
 
+  private def calculateStSetPointOption(wktA: String, index: Int, wktB: String): Option[String] =
+    calculateStSetPoint(wktA, index, wktB).headOption
+
+  private def calculateStSetPoint(wktA: String, index: Int, wktB: String): Array[String] =
+    Seq(Tuple3(wktReader.read(wktA), index, wktReader.read(wktB))).toDF("geomA", "index", "geomB")
+      .selectExpr(s"ST_SetPoint(geomA, index, geomB) as geom")
+      .filter("geom is not null")
+      .selectExpr("ST_AsText(geom)").as[String].collect()
+
   it("Passed ST_NumGeometries") {
     Given("Some different types of geometries in a DF")
     // Test data