From 05139ffe064cd4eb61ee24465176b1fc35ee0afb Mon Sep 17 00:00:00 2001 From: Matt Hicks Date: Thu, 5 Oct 2023 14:28:27 -0500 Subject: [PATCH] Added GeoJSON support --- build.sbt | 2 +- .../scala/com/outr/arango/geo/GeoJSON.scala | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 core/src/main/scala/com/outr/arango/geo/GeoJSON.scala diff --git a/build.sbt b/build.sbt index be866835..2d7e0c0d 100644 --- a/build.sbt +++ b/build.sbt @@ -7,7 +7,7 @@ val scala3 = "3.3.1" name := "scarango" ThisBuild / organization := "com.outr" -ThisBuild / version := "3.16.0" +ThisBuild / version := "3.17.0-SNAPSHOT" ThisBuild / scalaVersion := scala213 ThisBuild / crossScalaVersions := List(scala3, scala213) ThisBuild / scalacOptions ++= Seq("-unchecked", "-deprecation") diff --git a/core/src/main/scala/com/outr/arango/geo/GeoJSON.scala b/core/src/main/scala/com/outr/arango/geo/GeoJSON.scala new file mode 100644 index 00000000..2c8f1359 --- /dev/null +++ b/core/src/main/scala/com/outr/arango/geo/GeoJSON.scala @@ -0,0 +1,67 @@ +package com.outr.arango.geo + +import fabric._ +import fabric.define.DefType +import fabric.rw._ + +sealed trait GeoJSON + +object GeoJSON { + private def pointArray(p: Point): Json = arr(p.longitude, p.latitude) + private def pointFromCoords(json: Json): Point = { + val arr = json.asArr + Point( + latitude = arr.value(1).asDouble, + longitude = arr.value(0).asDouble + ) + } + private def pointsFromCoords(json: Json): List[Point] = json.asArr.value.toList.map(pointFromCoords) + private def multiPointsFromCoords(json: Json): List[List[Point]] = json.asArr.value.toList.map(pointsFromCoords) + private def createRW[T <: GeoJSON](toCoordinates: T => Json, fromCoordinates: Json => T): RW[T] = RW.from( + r = t => obj( + "coordinates" -> toCoordinates(t) + ), + w = j => fromCoordinates(j("coordinates")), + d = DefType.Json + ) + private lazy val pointRW: RW[Point] = createRW[Point]( + point => pointArray(point), + pointFromCoords + ) + private lazy val multiPointRW: RW[MultiPoint] = createRW[MultiPoint]( + mp => mp.points.map(pointArray).json, + json => MultiPoint(pointsFromCoords(json)) + ) + private lazy val lineStringRW: RW[LineString] = createRW[LineString]( + ls => ls.points.map(pointArray).json, + json => LineString(pointsFromCoords(json)) + ) + private lazy val multiLineStringRW: RW[MultiLineString] = createRW[MultiLineString]( + mls => mls.lines.map(_.map(pointArray)).json, + json => MultiLineString(multiPointsFromCoords(json)) + ) + private lazy val polygonRW: RW[Polygon] = createRW[Polygon]( + p => p.points.map(pointArray).json, + json => Polygon(pointsFromCoords(json)) + ) + private lazy val multiPolygonRW: RW[MultiPolygon] = createRW[MultiPolygon]( + mp => mp.polygons.map(_.map(pointArray)).json, + json => MultiPolygon(multiPointsFromCoords(json)) + ) + + implicit lazy val rw: RW[GeoJSON] = RW.poly[GeoJSON](getType = _.getClass.getSimpleName.replace("$", ""))( + "Point" -> pointRW, + "MultiPoint" -> multiPointRW, + "LineString" -> lineStringRW, + "MultiLineString" -> multiLineStringRW, + "Polygon" -> polygonRW, + "MultiPolygon" -> multiPolygonRW + ) + + case class Point(latitude: Double, longitude: Double) extends GeoJSON + case class MultiPoint(points: List[Point]) extends GeoJSON + case class LineString(points: List[Point]) extends GeoJSON + case class MultiLineString(lines: List[List[Point]]) extends GeoJSON + case class Polygon(points: List[Point]) extends GeoJSON + case class MultiPolygon(polygons: List[List[Point]]) extends GeoJSON +} \ No newline at end of file