All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lucuma.odb.json.declination.scala Maven / Gradle / Ivy

// Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA)
// For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause

package lucuma.odb.json

import cats.syntax.all.*
import io.circe.Decoder
import io.circe.DecodingFailure
import io.circe.Encoder
import io.circe.Json
import io.circe.syntax.*
import lucuma.core.math.Angle
import lucuma.core.math.Declination

import java.math.RoundingMode.HALF_UP

object declination {
  trait DecoderDeclination {
    given Decoder[Declination] =
      Decoder.instance { c =>
        def fromDecimal(field: String, µas: Long): Decoder.Result[Long] =
          c.downField(field).as[BigDecimal].map { bd =>
            (bd * µas).bigDecimal.setScale(0, HALF_UP).longValueExact
          }

        val micro: Decoder.Result[Declination] =
          c.downField("microarcseconds")
            .as[Long]
            .orElse(fromDecimal("degrees", Angle.µasPerDegree))
            .flatMap { l =>
              Declination.fromAngle
                .getOption(Angle.fromMicroarcseconds(l))
                .toRight(DecodingFailure("Invalid µarcsec value for declination", c.history))
            }

        def dms: Decoder.Result[Declination] =
          c.downField("dms")
            .as[String]
            .flatMap { s =>
              Declination.fromStringSignedDMS
                .getOption(s)
                .toRight(DecodingFailure(s"Could not parse `$s` as DD:MM:SS", c.history))
            }

        micro
          .orElse(dms)
          .orElse(DecodingFailure("Could not parse declination", c.history).asLeft)
      }
  }

  object decoder extends DecoderDeclination

  trait QueryCodec extends DecoderDeclination {

    given Encoder_Declination: Encoder[Declination] =
      Encoder.instance { dec =>
        Json.obj(
          "dms"             -> Declination.fromStringSignedDMS.reverseGet(dec).asJson,
          "degrees"         -> BigDecimal(dec.toAngle.toDoubleDegrees).asJson,
          "microarcseconds" -> dec.toAngle.toMicroarcseconds.asJson
        )
      }
  }

  object query extends QueryCodec

  trait TransportCodec extends DecoderDeclination {

    given Encoder_Declination: Encoder[Declination] =
      Encoder.instance { dec =>
        Json.obj(
          "microarcseconds" -> dec.toAngle.toMicroarcseconds.asJson
        )
      }
  }

  object transport extends TransportCodec
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy