// Ported from topojson-client src/untransform.js; Math.round uses floor(x + 0.5).

///|
pub struct Quantizer {
  priv scale : Array[Double]
  priv translate : Array[Double]
} derive(Debug)

///|
pub fn quantizer(
  scale : Array[Double],
  translate : Array[Double],
) -> Quantizer raise TopoError {
  if scale.length() != 2 || translate.length() != 2 {
    raise Invalid("transform.dimension")
  }
  for n in scale {
    if !finite(n) || n == 0.0 || n.abs() > 1.0e12 {
      raise Invalid("transform.scale")
    }
  }
  for n in translate {
    if !finite(n) || n.abs() > 1.0e12 {
      raise Invalid("transform.translate")
    }
  }
  { scale: scale.copy(), translate: translate.copy(), }
}

///|
pub fn Quantizer::point(
  self : Quantizer,
  p : Array[Double],
) -> Array[Double] raise TopoError {
  check_position(p.to_json())
  let out = p.copy()
  for i = 0; i < 2; i = i + 1 {
    let v = @double.floor((p[i] - self.translate[i]) / self.scale[i] + 0.5)
    if !finite(v) || v.abs() > 1.0e12 {
      raise Invalid("quantize.range")
    }
    out[i] = v
  }
  out
}

///|
/// Quantize and delta-encode; discard consecutive coincident positions.
pub fn Quantizer::arc(
  self : Quantizer,
  points : Array[Array[Double]],
) -> Array[Array[Double]] raise TopoError {
  if points.length() < 2 || points.length() > 1000000 {
    raise Invalid("arc.size")
  }
  let first = self.point(points[0])
  let out = [first]
  let mut x = first[0]
  let mut y = first[1]
  for i = 1; i < points.length(); i = i + 1 {
    let p = self.point(points[i])
    let nx = p[0]
    let ny = p[1]
    p[0] -= x
    p[1] -= y
    x = nx
    y = ny
    if p[0] != 0.0 || p[1] != 0.0 {
      out.push(p)
    }
  }
  if out.length() == 1 {
    out.push([0.0, 0.0])
  }
  out
}