diff --git a/modules/postgis/src/main/scala/ewkb/codecs.scala b/modules/postgis/src/main/scala/ewkb/codecs.scala index db9e5ea0..60b97904 100644 --- a/modules/postgis/src/main/scala/ewkb/codecs.scala +++ b/modules/postgis/src/main/scala/ewkb/codecs.scala @@ -107,31 +107,41 @@ trait EWKBPrimitives { srid :: provide(ewkb.coordinate) :: listOfN(gint32, coordinate) }.as[LineString] + private case class PolygonRepr(srid: Option[SRID], dim: Dimension, rings: List[LinearRing]) def polygon(implicit byteOrdering: ByteOrdering, ewkb: EWKBType): Scodec[Polygon] = { - listOfN(gint32, linearRing).xmap[Polygon]( - rings => rings match { - case shell :: holes => Polygon(None, ewkb.coordinate, Some(shell), holes) - case Nil => Polygon(None, ewkb.coordinate, None, Nil) - }, - polygon => polygon.shell.toList ::: polygon.holes + (srid :: provide(ewkb.coordinate) :: listOfN(gint32, linearRing)).as[PolygonRepr].xmap[Polygon]( + repr => Polygon(repr.srid, repr.dim, repr.rings.headOption, repr.rings.drop(1)), + p => PolygonRepr(p.srid, p.dimension, p.shell.toList ::: p.holes) ) - }.as[Polygon] + } def linearRing(implicit byteOrdering: ByteOrdering, ewkb: EWKBType): Scodec[LinearRing] = { - listOfN(guint32.xmap(_.toInt, _.toLong), coordinate) - .xmap[NonEmptyList[Coordinate]](NonEmptyList.fromListUnsafe, _.toList) + listOfN(gint32, coordinate).xmap[NonEmptyList[Coordinate]](NonEmptyList.fromListUnsafe, _.toList) }.as[LinearRing] def multiPoint(implicit byteOrdering: ByteOrdering, ewkb: EWKBType): Scodec[MultiPoint] = { - srid :: provide(ewkb.coordinate) :: listOfN(gint32, geometry.downcast[Point]) + srid :: provide(ewkb.coordinate) :: listOfN(gint32, geometry.downcast[Point]).xmap[List[Point]]( + pts => pts.map(_.copy(srid = None)), + identity + ) }.as[MultiPoint] def multiLineString(implicit byteOrdering: ByteOrdering, ewkb: EWKBType): Scodec[MultiLineString] = { - srid :: provide(ewkb.coordinate) :: listOfN(gint32, geometry.downcast[LineString]) + srid.flatPrepend { srid => + provide(ewkb.coordinate) :: listOfN(gint32, geometry.downcast[LineString]).xmap[List[LineString]]( + lss => lss.map(_.copy(srid = srid)), + identity + ) + } }.as[MultiLineString] def multiPolygon(implicit byteOrdering: ByteOrdering, ewkb: EWKBType): Scodec[MultiPolygon] = { - srid :: provide(ewkb.coordinate) :: listOfN(gint32, geometry.downcast[Polygon]) + srid.flatPrepend { srid => + provide(ewkb.coordinate) :: listOfN(gint32, geometry.downcast[Polygon]).xmap[List[Polygon]]( + ps => ps.map(_.copy(srid = srid)), + identity + ) + } }.as[MultiPolygon] def geometryCollection(implicit byteOrdering: ByteOrdering, ewkb: EWKBType): Scodec[GeometryCollection] = { diff --git a/modules/postgis/src/main/scala/ewkt/parser.scala b/modules/postgis/src/main/scala/ewkt/parser.scala index 8790db21..ab98a53c 100644 --- a/modules/postgis/src/main/scala/ewkt/parser.scala +++ b/modules/postgis/src/main/scala/ewkt/parser.scala @@ -19,6 +19,23 @@ object EWKT { private[this] val whitespaces0: P[Unit] = whitespace.rep.void private[this] val comma: P[Unit] = P.char(',').surroundedBy(whitespaces0.?) + private[this] implicit class BetweenOps[A](parser: P[A]) { + implicit val betweenParens: P[A] = + parser.between(P.char('('), P.char(')')) + implicit val betweenParensOpt: P[A] = + parser.between(P.char('(').?, P.char(')').?) + } + + private[this] val srid: P[SRID] = + Numbers.nonNegativeIntString.map(s => SRID(Integer.parseInt(s))).between( + P.ignoreCase("SRID="), + P.char(';') + ) + + private[this] def keyword(keyword: String): P[Dimension] = + P.ignoreCase(keyword).surroundedBy(whitespaces0.?) *> + dimension + // This is only a hint, if you leave off ZM, but provide the 4 dimensions in the coordinate, it's still ZM // Both 'POINT( 1 2 3 4 )' and 'POINT ZM( 1 2 3 4 )' have the same dimension private[this] val dimension: P0[Dimension] = ( @@ -33,16 +50,12 @@ object EWKT { } } - private[this] implicit class BetweenOps[A](parser: P[A]) { - implicit val betweenParens: P[A] = - parser.between(P.char('('), P.char(')')) - implicit val betweenParensOpt: P[A] = - parser.between(P.char('(').?, P.char(')').?) - } + private[this] def empty[A](value: A): P[A] = + P.ignoreCase("EMPTY").surroundedBy(whitespaces0.?).as(value) private[this] val double: P[Double] = Numbers.jsonNumber.map(s => BigDecimal(s).toDouble) - + private[this] def coordinate(implicit dimensionHint: Dimension): P[Coordinate] = double.surroundedBy(whitespaces0.?).rep(2, 4).flatMap { elements => (elements, dimensionHint) match { @@ -69,40 +82,33 @@ object EWKT { private[this] def coordinates(implicit dimensionHint: Dimension): P[NonEmptyList[Coordinate]] = coordinate.repSep(comma).betweenParens - private[this] def keyword(keyword: String): P[Dimension] = - P.ignoreCase(keyword).surroundedBy(whitespaces0.?) *> - dimension - - private[this] def empty[A](value: A): P[A] = - P.ignoreCase("EMPTY").surroundedBy(whitespaces0.?).as(value) - ///////////////////////////////////////////////////////////////////////////// - private[this] def nonEmptyPoint(implicit dimensionHint: Dimension): P[Point] = - coordinate.betweenParens.map(c => Point(c)) + private[this] def nonEmptyPoint(implicit srid: Option[SRID], dimensionHint: Dimension): P[Point] = + coordinate.betweenParens.map(c => Point(srid, c)) - private[this] def nonEmptyLineString(implicit dimensionHint: Dimension): P[LineString] = + private[this] def nonEmptyLineString(implicit srid: Option[SRID], dimensionHint: Dimension): P[LineString] = coordinate.repSep(comma).betweenParens.map(points => - LineString(None, dimensionHint, points.toList)) + LineString(srid, dimensionHint, points.toList)) - private[this] def nonEmptyPolygon(implicit dimensionHint: Dimension): P[Polygon] = + private[this] def nonEmptyPolygon(implicit srid: Option[SRID], dimensionHint: Dimension): P[Polygon] = coordinates.map(LinearRing.apply).repSep(comma).betweenParens.map(rings => - Polygon(None, dimensionHint, Some(rings.head), rings.tail)) + Polygon(srid, dimensionHint, Some(rings.head), rings.tail)) - private[this] def nonEmptyMultiPoint(implicit dimensionHint: Dimension): P[MultiPoint] = + private[this] def nonEmptyMultiPoint(implicit srid: Option[SRID], dimensionHint: Dimension): P[MultiPoint] = coordinate.betweenParensOpt.repSep(comma) .map(nel => nel.map(c => Point(c))).betweenParensOpt - .map(points => MultiPoint(None, dimensionHint, points.toList)) + .map(points => MultiPoint(srid, dimensionHint, points.toList)) - private[this] def nonEmptyMultiLineString(implicit dimensionHint: Dimension): P[MultiLineString] = + private[this] def nonEmptyMultiLineString(implicit srid: Option[SRID], dimensionHint: Dimension): P[MultiLineString] = nonEmptyLineString.repSep(comma).betweenParens.map(lineStrings => - MultiLineString(None, dimensionHint, lineStrings.toList)) + MultiLineString(srid, dimensionHint, lineStrings.toList)) - private[this] def nonEmptyMultiPolygon(implicit dimensionHint: Dimension): P[MultiPolygon] = + private[this] def nonEmptyMultiPolygon(implicit srid: Option[SRID], dimensionHint: Dimension): P[MultiPolygon] = nonEmptyPolygon.repSep(comma).betweenParens.map(polygons => - MultiPolygon(None, dimensionHint, polygons.toList)) + MultiPolygon(srid, dimensionHint, polygons.toList)) - private[this] def nonEmptyGeometryCollection(implicit dimensionHint: Dimension): P[GeometryCollection] = + private[this] def nonEmptyGeometryCollection(implicit srid: Option[SRID], dimensionHint: Dimension): P[GeometryCollection] = P.oneOf( point :: lineString :: @@ -113,83 +119,97 @@ object EWKT { geometryCollection :: Nil ).repSep(comma).betweenParens.map(geometries => - GeometryCollection(None, dimensionHint, geometries.toList) + GeometryCollection(srid, dimensionHint, geometries.toList) ) ///////////////////////////////////////////////////////////////////////////// - val point: P[Point] = - keyword("POINT").flatMap { implicit dimensionHint => - P.oneOf( - coordinateEmpty.map(c => Point(c)) :: - nonEmptyPoint :: - Nil - ) + def point: P[Point] = + P.flatMap01(srid.?) { implicit srid => + keyword("POINT").flatMap { implicit dimensionHint => + P.oneOf( + coordinateEmpty.map(c => Point(srid, c)) :: + nonEmptyPoint :: + Nil + ) + } } val lineString: P[LineString] = - keyword("LINESTRING").flatMap { implicit dimensionHint => - P.oneOf( - empty(LineString.empty(dimensionHint)) :: - nonEmptyLineString :: - Nil - ) + P.flatMap01(srid.?) { implicit srid => + keyword("LINESTRING").flatMap { implicit dimensionHint => + P.oneOf( + empty(LineString(srid, dimensionHint, Nil)) :: + nonEmptyLineString :: + Nil + ) + } } val polygon: P[Polygon] = - keyword("POLYGON").flatMap { implicit dimensionHint => - P.oneOf( - empty(Polygon.empty(dimensionHint)) :: - nonEmptyPolygon :: - Nil - ) + P.flatMap01(srid.?) { implicit srid => + keyword("POLYGON").flatMap { implicit dimensionHint => + P.oneOf( + empty(Polygon(srid, dimensionHint, None, Nil)) :: + nonEmptyPolygon :: + Nil + ) + } } val multiPoint: P[MultiPoint] = - keyword("MULTIPOINT").flatMap { implicit dimensionHint => - P.oneOf( - empty(MultiPoint.empty(dimensionHint)) :: - nonEmptyMultiPoint :: - Nil - ) + P.flatMap01(srid.?) { implicit srid => + keyword("MULTIPOINT").flatMap { implicit dimensionHint => + P.oneOf( + empty(MultiPoint(srid, dimensionHint, Nil)) :: + nonEmptyMultiPoint :: + Nil + ) + } } val multiLineString: P[MultiLineString] = - keyword("MULTILINESTRING").flatMap { implicit dimensionHint => - P.oneOf( - empty(MultiLineString.empty(dimensionHint)) :: - nonEmptyMultiLineString :: - Nil - ) + P.flatMap01(srid.?) { implicit srid => + keyword("MULTILINESTRING").flatMap { implicit dimensionHint => + P.oneOf( + empty(MultiLineString(srid, dimensionHint, Nil)) :: + nonEmptyMultiLineString :: + Nil + ) + } } val multiPolygon: P[MultiPolygon] = - keyword("MULTIPOLYGON").flatMap { implicit dimensionHint => - P.oneOf( - empty(MultiPolygon.empty(dimensionHint)) :: - nonEmptyMultiPolygon :: - Nil - ) + P.flatMap01(srid.?) { implicit srid => + keyword("MULTIPOLYGON").flatMap { implicit dimensionHint => + P.oneOf( + empty(MultiPolygon(srid, dimensionHint, Nil)) :: + nonEmptyMultiPolygon :: + Nil + ) + } } val geometryCollection: P[GeometryCollection] = - keyword("GEOMETRYCOLLECTION").flatMap { implicit dimensionHint => - P.oneOf( - empty(GeometryCollection.empty(dimensionHint)) :: - nonEmptyGeometryCollection :: - Nil - ) + P.flatMap01(srid.?) { implicit srid => + keyword("GEOMETRYCOLLECTION").flatMap { implicit dimensionHint => + P.oneOf( + empty(GeometryCollection(srid, dimensionHint, Nil)) :: + nonEmptyGeometryCollection :: + Nil + ) + } } val geometry: P[Geometry] = P.oneOf( - point :: - lineString :: - polygon :: - multiPoint :: - multiLineString :: - multiPolygon :: - geometryCollection :: + point.backtrack :: + lineString.backtrack :: + polygon.backtrack :: + multiPoint.backtrack :: + multiLineString.backtrack :: + multiPolygon.backtrack :: + geometryCollection.backtrack :: Nil ) } \ No newline at end of file diff --git a/modules/postgis/src/main/scala/geometry.scala b/modules/postgis/src/main/scala/geometry.scala index 0d1cbb60..4dd2ecb0 100644 --- a/modules/postgis/src/main/scala/geometry.scala +++ b/modules/postgis/src/main/scala/geometry.scala @@ -70,7 +70,7 @@ object Coordinate { def xyzm(x: Double, y: Double, z: Double, m: Double): Coordinate = Coordinate(x, y, z.some, m.some) } -final case class Point private (srid: Option[SRID], coordinate: Coordinate) extends Geometry { +final case class Point (srid: Option[SRID], coordinate: Coordinate) extends Geometry { override def dimension: Dimension = coordinate.dimension } @@ -89,13 +89,11 @@ object Point { def xyzm(srid: SRID, x: Double, y: Double, z: Double, m: Double): Point = Point(srid.some, Coordinate.xyzm(x, y, z, m)) } -final case class LineString(srid: Option[SRID], private val dimensionHint: Dimension, coordinates: List[Coordinate]) extends Geometry { +final case class LineString(srid: Option[SRID], dimensionHint: Dimension, coordinates: List[Coordinate]) extends Geometry { override def dimension: Dimension = coordinates.headOption.fold(dimensionHint)(_.dimension) } object LineString { - def empty(dimension: Dimension): LineString = LineString(None, dimension, Nil) - def apply(coordinates: Coordinate*): LineString = apply(coordinates.toList) def apply(coordinates: List[Coordinate]): LineString = @@ -114,13 +112,11 @@ object LinearRing { LinearRing(NonEmptyList(head, tail.toList)) } -final case class Polygon(srid: Option[SRID], private val dimensionHint: Dimension, shell: Option[LinearRing], holes: List[LinearRing]) extends Geometry { +final case class Polygon(srid: Option[SRID], dimensionHint: Dimension, shell: Option[LinearRing], holes: List[LinearRing]) extends Geometry { override def dimension: Dimension = shell.map(_.coordinates.head.dimension).getOrElse(dimensionHint) } object Polygon { - def empty(dimension: Dimension): Polygon = Polygon(None, dimension, None, Nil) - def apply(shell: LinearRing): Polygon = Polygon(None, shell.coordinates.head.dimension, shell.some, Nil) def apply(shell: LinearRing, holes: LinearRing*): Polygon = @@ -132,13 +128,11 @@ object Polygon { Polygon(srid.some, shell.coordinates.head.dimension, shell.some, holes.toList) } -final case class MultiPoint(srid: Option[SRID], private val dimensionHint: Dimension, points: List[Point]) extends Geometry { +final case class MultiPoint(srid: Option[SRID], dimensionHint: Dimension, points: List[Point]) extends Geometry { override def dimension: Dimension = points.headOption.fold(dimensionHint)(_.dimension) } object MultiPoint { - def empty(dimension: Dimension): MultiPoint = MultiPoint(None, dimension, Nil) - def apply(points: Point*): MultiPoint = MultiPoint(None, points.headOption.fold[Dimension](Dimension.TwoD)(_.dimension), points.toList) @@ -146,13 +140,11 @@ object MultiPoint { MultiPoint(srid.some, points.headOption.fold[Dimension](Dimension.TwoD)(_.dimension), points.toList) } -final case class MultiLineString(srid: Option[SRID], private val dimensionHint: Dimension, lineStrings: List[LineString]) extends Geometry { +final case class MultiLineString(srid: Option[SRID], dimensionHint: Dimension, lineStrings: List[LineString]) extends Geometry { override def dimension: Dimension = lineStrings.headOption.fold(dimensionHint)(_.dimension) } object MultiLineString { - def empty(dimension: Dimension): MultiLineString = MultiLineString(None, dimension, Nil) - def apply(lineStrings: LineString*): MultiLineString = MultiLineString(None, lineStrings.headOption.fold[Dimension](Dimension.TwoD)(_.dimension), lineStrings.toList) @@ -160,13 +152,11 @@ object MultiLineString { MultiLineString(srid.some, lineStrings.headOption.fold[Dimension](Dimension.TwoD)(_.dimension), lineStrings.toList) } -final case class MultiPolygon(srid: Option[SRID], private val dimensionHint: Dimension, polygons: List[Polygon]) extends Geometry { +final case class MultiPolygon(srid: Option[SRID], dimensionHint: Dimension, polygons: List[Polygon]) extends Geometry { override def dimension: Dimension = polygons.headOption.fold(dimensionHint)(_.dimension) } object MultiPolygon { - def empty(dimension: Dimension): MultiPolygon = MultiPolygon(None, dimension, Nil) - def apply(polygons: Polygon*): MultiPolygon = MultiPolygon(None, polygons.headOption.fold[Dimension](Dimension.TwoD)(_.dimension), polygons.toList) @@ -174,12 +164,11 @@ object MultiPolygon { MultiPolygon(srid.some, polygons.headOption.fold[Dimension](Dimension.TwoD)(_.dimension), polygons.toList) } -final case class GeometryCollection(srid: Option[SRID], private val dimensionHint: Dimension, geometries: List[Geometry]) extends Geometry { +final case class GeometryCollection(srid: Option[SRID], dimensionHint: Dimension, geometries: List[Geometry]) extends Geometry { override def dimension: Dimension = geometries.headOption.fold(dimensionHint)(_.dimension) } object GeometryCollection { - def empty(dimension: Dimension): GeometryCollection = GeometryCollection(None, dimension, Nil) def apply(geometries: Geometry*): GeometryCollection = GeometryCollection(None, geometries.headOption.fold[Dimension](Dimension.TwoD)(_.dimension), geometries.toList) diff --git a/modules/tests/shared/src/test/scala/codec/PostGISCodecTest.scala b/modules/tests/shared/src/test/scala/codec/PostGISCodecTest.scala index 6b2cfe11..7a2f13db 100644 --- a/modules/tests/shared/src/test/scala/codec/PostGISCodecTest.scala +++ b/modules/tests/shared/src/test/scala/codec/PostGISCodecTest.scala @@ -58,10 +58,12 @@ class PostGISCodecTest extends CodecTest(strategy = Typer.Strategy.SearchPath) { MultiLineString( SRID(4326), LineString( + SRID(4326), Coordinate.xy(0, 0), Coordinate.xy(1, 1) ), LineString( + SRID(4326), Coordinate.xy(2, 2), Coordinate.xy(3, 3) ) @@ -72,6 +74,7 @@ class PostGISCodecTest extends CodecTest(strategy = Typer.Strategy.SearchPath) { MultiPolygon( SRID(4326), Polygon( + SRID(4326), LinearRing( Coordinate.xy(0, 0), Coordinate.xy(10, 10), diff --git a/modules/tests/shared/src/test/scala/postgis/RoundtripTest.scala b/modules/tests/shared/src/test/scala/postgis/RoundtripTest.scala index 52ffec62..650cad10 100644 --- a/modules/tests/shared/src/test/scala/postgis/RoundtripTest.scala +++ b/modules/tests/shared/src/test/scala/postgis/RoundtripTest.scala @@ -77,11 +77,17 @@ class RoundtripTest extends SkunkTest(strategy = Typer.Strategy.SearchPath) { roundtripEWKT("GEOMETRYCOLLECTION M EMPTY") roundtripEWKT("GEOMETRYCOLLECTION ZM EMPTY") roundtripEWKT("GEOMETRYCOLLECTION ZM (POINT ZM (0 0 0 0),LINESTRING ZM (0 0 0 0,1 1 1 1))") - roundtripEWKT("GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1))") + roundtripEWKT("SRID=4326;GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1))") roundtripEWKT("GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1),GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1)))") roundtripEWKT("GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1),POINT M EMPTY,GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1)))") roundtripEWKT("GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1),GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1),POINT M EMPTY,GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1))),POINT M EMPTY,GEOMETRYCOLLECTION M (POINT M (0 0 0),LINESTRING M (0 0 0,1 1 1)))") + roundtripEWKT("SRID=4326;POINT(-44.3 60.1)") + roundtripEWKT("SRID=4326;LINESTRING(-71.160281 42.258729,-71.160837 42.259113,-71.161144 42.25932)") + roundtripEWKT("SRID=4269;POLYGON((-71.1776585052917 42.3902909739571,-71.1776820268866 42.3903701743239,-71.1776063012595 42.3903825660754,-71.1775826583081 42.3903033653531,-71.1776585052917 42.3902909739571))") + roundtripEWKT("SRID=4269;MULTILINESTRING((-71.160281 42.258729,-71.160837 42.259113,-71.161144 42.25932))") + roundtripEWKT("SRID=4269;MULTIPOLYGON(((-71.1031880899493 42.3152774590236,-71.1031627617667 42.3152960829043,-71.102923838298 42.3149156848307,-71.1023097974109 42.3151969047397,-71.1019285062273 42.3147384934248,-71.102505233663 42.3144722937587,-71.10277487471 42.3141658254797,-71.103113945163 42.3142739188902,-71.10324876416 42.31402489987,-71.1033002961013 42.3140393340215,-71.1033488797549 42.3139495090772,-71.103396240451 42.3138632439557,-71.1041521907712 42.3141153348029,-71.1041411411543 42.3141545014533,-71.1041287795912 42.3142114839058,-71.1041188134329 42.3142693656241,-71.1041112482575 42.3143272556118,-71.1041072845732 42.3143851580048,-71.1041057218871 42.3144430686681,-71.1041065602059 42.3145009876017,-71.1041097995362 42.3145589148055,-71.1041166403905 42.3146168544148,-71.1041258822717 42.3146748022936,-71.1041375307579 42.3147318674446,-71.1041492906949 42.3147711126569,-71.1041598612795 42.314808571739,-71.1042515013869 42.3151287620809,-71.1041173835118 42.3150739481917,-71.1040809891419 42.3151344119048,-71.1040438678912 42.3151191367447,-71.1040194562988 42.3151832057859,-71.1038734225584 42.3151140942995,-71.1038446938243 42.3151006300338,-71.1038315271889 42.315094347535,-71.1037393329282 42.315054824985,-71.1035447555574 42.3152608696313,-71.1033436658644 42.3151648370544,-71.1032580383161 42.3152269126061,-71.103223066939 42.3152517403219,-71.1031880899493 42.3152774590236)),((-71.1043632495873 42.315113108546,-71.1043583974082 42.3151211109857,-71.1043443253471 42.3150676015829,-71.1043850704575 42.3150793250568,-71.1043632495873 42.315113108546)))") + // Round trip Skunk EWKT parse => PostGIS EWKT encode => Skunk EWKB decode private def roundtripEWKT(ewkt: String) = { sessionTest(ewkt) { s => diff --git a/modules/tests/shared/src/test/scala/postgis/ewkb/EWKBTest.scala b/modules/tests/shared/src/test/scala/postgis/ewkb/EWKBTest.scala index 3a6c1f6d..3bf8de1f 100644 --- a/modules/tests/shared/src/test/scala/postgis/ewkb/EWKBTest.scala +++ b/modules/tests/shared/src/test/scala/postgis/ewkb/EWKBTest.scala @@ -75,6 +75,22 @@ class EWKBTest extends munit.FunSuite { ) ) + ewkbTest("SRID=4269;POLYGON((-71.1776585052917 42.3902909739571,-71.1776820268866 42.3903701743239,-71.1776063012595 42.3903825660754,-71.1775826583081 42.3903033653531,-71.1776585052917 42.3902909739571))")( + hex"0103000020AD10000001000000050000006285C7C15ECB51C0ED88FC0DF531454028A46F245FCB51C009075EA6F731454047DED1E65DCB51C0781C510EF83145404871A7835DCB51C0EBDAEE75F53145406285C7C15ECB51C0ED88FC0DF5314540", + Polygon( + SRID(4269).some, + Dimension.TwoD, + LinearRing( + Coordinate.xy(-71.1776585052917, 42.3902909739571), + Coordinate.xy(-71.1776820268866, 42.3903701743239), + Coordinate.xy(-71.1776063012595, 42.3903825660754), + Coordinate.xy(-71.1775826583081, 42.3903033653531), + Coordinate.xy(-71.1776585052917, 42.3902909739571) + ).some, + Nil + ) + ) + ewkbTest("POLYGON((-15.66486 27.91996, -15.60610 27.91820, -15.60359 27.97169, -15.66586 27.97144,-15.66486 27.91996), (-15.65753 27.95894, -15.61610 27.95995, -15.61459 27.93157,-15.65477 27.93007,-15.65753 27.95894))")( hex"010300000002000000050000004DD6A88768542FC0CFA0A17F82EB3B4011363CBD52362FC0EC2FBB270FEB3B40A2629CBF09352FC0A9D903ADC0F83B40DB6D179AEB542FC0B806B64AB0F83B404DD6A88768542FC0CFA0A17F82EB3B40050000001B47ACC5A7502FC084D382177DF53B4096218E75713B2FC092CB7F48BFF53B40B4E55C8AAB3A2FC04AEF1B5F7BEE3B40C8CD70033E4F2FC0A0FD481119EE3B401B47ACC5A7502FC084D382177DF53B40", Polygon(