diff --git a/src/main/scala/com/databricks/labs/mosaic/core/geometry/polygon/MosaicPolygonJTS.scala b/src/main/scala/com/databricks/labs/mosaic/core/geometry/polygon/MosaicPolygonJTS.scala index 6487f2f66..33605eaa8 100644 --- a/src/main/scala/com/databricks/labs/mosaic/core/geometry/polygon/MosaicPolygonJTS.scala +++ b/src/main/scala/com/databricks/labs/mosaic/core/geometry/polygon/MosaicPolygonJTS.scala @@ -84,14 +84,29 @@ object MosaicPolygonJTS extends GeometryReader { val newGeom = GeometryTypeEnum.fromString(geomSeq.head.getGeometryType) match { case POINT => val extractedPoints = geomSeq.map(_.asInstanceOf[MosaicPointJTS]) - val exteriorRing = extractedPoints.map(_.coord).toArray ++ Array(extractedPoints.head.coord) + val exteriorRing = + if (extractedPoints.head.coord == extractedPoints.last.coord) { + extractedPoints.map(_.coord).toArray + } else { + extractedPoints.map(_.coord).toArray ++ Array(extractedPoints.head.coord) + } gf.createPolygon(exteriorRing) case LINESTRING => val extractedLines = geomSeq.map(_.asInstanceOf[MosaicLineStringJTS]) val exteriorRing = - gf.createLinearRing(extractedLines.head.asSeq.map(_.coord).toArray ++ Array(extractedLines.head.asSeq.head.coord)) + if (extractedLines.head.asSeq.head.coord == extractedLines.head.asSeq.last.coord) { + gf.createLinearRing(extractedLines.head.asSeq.map(_.coord).toArray) + } else { + gf.createLinearRing(extractedLines.head.asSeq.map(_.coord).toArray ++ Array(extractedLines.head.asSeq.head.coord)) + } val holes = extractedLines.tail - .map({ h: MosaicLineStringJTS => h.asSeq.map(_.coord).toArray ++ Array(h.asSeq.head.coord) }) + .map({ h: MosaicLineStringJTS => + if (h.asSeq.head.coord == h.asSeq.last.coord) { + h.asSeq.map(_.coord).toArray + } else { + h.asSeq.map(_.coord).toArray ++ Array(h.asSeq.head.coord) + } + }) .map(gf.createLinearRing) .toArray gf.createPolygon(exteriorRing, holes) diff --git a/src/test/scala/com/databricks/labs/mosaic/core/geometry/polygon/TestPolygonJTS.scala b/src/test/scala/com/databricks/labs/mosaic/core/geometry/polygon/TestPolygonJTS.scala index 498e2f84f..f63fbc9e2 100644 --- a/src/test/scala/com/databricks/labs/mosaic/core/geometry/polygon/TestPolygonJTS.scala +++ b/src/test/scala/com/databricks/labs/mosaic/core/geometry/polygon/TestPolygonJTS.scala @@ -42,11 +42,16 @@ class TestPolygonJTS extends AnyFlatSpec { "MosaicPolygonJTS" should "be instantiable from a Seq of MosaicPointJTS" in { val polygonReference = MosaicPolygonJTS.fromWKT("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))") - val pointSeq = Seq("POINT (30 10)", "POINT (40 40)", "POINT (20 40)", "POINT (10 20)") + val pointSeq_open = Seq("POINT (30 10)", "POINT (40 40)", "POINT (20 40)", "POINT (10 20)") .map(MosaicPointJTS.fromWKT) .map(_.asInstanceOf[MosaicPointJTS]) - val polygonTest = MosaicPolygonJTS.fromSeq(pointSeq) - polygonReference.equals(polygonTest) shouldBe true + val pointSeq_closed = Seq("POINT (30 10)", "POINT (40 40)", "POINT (20 40)", "POINT (10 20)", "POINT (30 10)") + .map(MosaicPointJTS.fromWKT) + .map(_.asInstanceOf[MosaicPointJTS]) + val polygonTest_open = MosaicPolygonJTS.fromSeq(pointSeq_open) + val polygonTest_closed = MosaicPolygonJTS.fromSeq(pointSeq_closed) + polygonReference.equals(polygonTest_open) shouldBe true + polygonReference.equals(polygonTest_closed) shouldBe true } "MosaicPolygonJTS" should "not fail for empty Seq" in { @@ -59,11 +64,16 @@ class TestPolygonJTS extends AnyFlatSpec { "MosaicPolygonJTS" should "be instantiable from a Seq of MosaicLineStringJTS" in { val polygonReference = MosaicPolygonJTS.fromWKT("POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))") - val linesSeq = Seq("LINESTRING (35 10, 45 45, 15 40, 10 20)", "LINESTRING (20 30, 35 35, 30 20)") + val linesSeq_open = Seq("LINESTRING (35 10, 45 45, 15 40, 10 20)", "LINESTRING (20 30, 35 35, 30 20)") + .map(MosaicLineStringJTS.fromWKT) + .map(_.asInstanceOf[MosaicLineStringJTS]) + val linesSeq_closed = Seq("LINESTRING (35 10, 45 45, 15 40, 10 20, 35 10)", "LINESTRING (20 30, 35 35, 30 20, 20 30)") .map(MosaicLineStringJTS.fromWKT) .map(_.asInstanceOf[MosaicLineStringJTS]) - val polygonTest = MosaicPolygonJTS.fromSeq(linesSeq) - polygonReference.equals(polygonTest) shouldBe true + val polygonTest_open = MosaicPolygonJTS.fromSeq(linesSeq_open) + val polygonTest_closed = MosaicPolygonJTS.fromSeq(linesSeq_closed) + polygonReference.equals(polygonTest_open) shouldBe true + polygonReference.equals(polygonTest_closed) shouldBe true } "MosaicPolygonJTS" should "return a Seq of MosaicLineStringJTS object when calling asSeq" in { diff --git a/src/test/scala/com/databricks/labs/mosaic/core/index/TestCustomIndexSystem.scala b/src/test/scala/com/databricks/labs/mosaic/core/index/TestCustomIndexSystem.scala index b20a19c91..022de18a4 100644 --- a/src/test/scala/com/databricks/labs/mosaic/core/index/TestCustomIndexSystem.scala +++ b/src/test/scala/com/databricks/labs/mosaic/core/index/TestCustomIndexSystem.scala @@ -118,16 +118,16 @@ class TestCustomIndexSystem extends AnyFunSuite { // First quadrant val wkt0 = grid.indexToGeometry(0 | resolutionMask, JTS).toWKT - wkt0 shouldBe "POLYGON ((0 0, 50 0, 50 50, 0 50, 0 0, 0 0))" + wkt0 shouldBe "POLYGON ((0 0, 50 0, 50 50, 0 50, 0 0))" val wkt1 = grid.indexToGeometry(1 | resolutionMask, JTS).toWKT - wkt1 shouldBe "POLYGON ((50 0, 100 0, 100 50, 50 50, 50 0, 50 0))" + wkt1 shouldBe "POLYGON ((50 0, 100 0, 100 50, 50 50, 50 0))" val wkt2 = grid.indexToGeometry(2 | resolutionMask, JTS).toWKT - wkt2 shouldBe "POLYGON ((0 50, 50 50, 50 100, 0 100, 0 50, 0 50))" + wkt2 shouldBe "POLYGON ((0 50, 50 50, 50 100, 0 100, 0 50))" val wkt3 = grid.indexToGeometry(3 | resolutionMask, JTS).toWKT - wkt3 shouldBe "POLYGON ((50 50, 100 50, 100 100, 50 100, 50 50, 50 50))" + wkt3 shouldBe "POLYGON ((50 50, 100 50, 100 100, 50 100, 50 50))" } test("polyfill single cell") {