package scala.ray_casting

case class Edge(_1: (Double, Double), _2: (Double, Double)) {
  import Math._
  import Double._

  def raySegI(p: (Double, Double)): Boolean = {
    if (_1._2 > _2._2) return Edge(_2, _1).raySegI(p)
    if (p._2 == _1._2 || p._2 == _2._2) return raySegI((p._1, p._2 + epsilon))
    if (p._2 > _2._2 || p._2 < _1._2 || p._1 > max(_1._1, _2._1))
      return false
    if (p._1 < min(_1._1, _2._1)) return true
    val blue = if (abs(_1._1 - p._1) > MinValue) (p._2 - _1._2) / (p._1 - _1._1) else MaxValue
    val red = if (abs(_1._1 - _2._1) > MinValue) (_2._2 - _1._2) / (_2._1 - _1._1) else MaxValue
    blue >= red
  }

  final val epsilon = 0.00001
}

case class Figure(name: String, edges: Seq[Edge]) {
  def contains(p: (Double, Double)) = edges.count(_.raySegI(p)) % 2 != 0
}

object Ray_casting extends App {
  val figures = Seq(Figure("Square", Seq(((0.0, 0.0), (10.0, 0.0)), ((10.0, 0.0), (10.0, 10.0)),
    ((10.0, 10.0), (0.0, 10.0)),((0.0, 10.0), (0.0, 0.0)))),
    Figure("Square hole", Seq(((0.0, 0.0), (10.0, 0.0)), ((10.0, 0.0), (10.0, 10.0)),
      ((10.0, 10.0), (0.0, 10.0)), ((0.0, 10.0), (0.0, 0.0)), ((2.5, 2.5), (7.5, 2.5)),
      ((7.5, 2.5), (7.5, 7.5)),((7.5, 7.5), (2.5, 7.5)), ((2.5, 7.5), (2.5, 2.5)))),
    Figure("Strange", Seq(((0.0, 0.0), (2.5, 2.5)), ((2.5, 2.5), (0.0, 10.0)),
      ((0.0, 10.0), (2.5, 7.5)), ((2.5, 7.5), (7.5, 7.5)), ((7.5, 7.5), (10.0, 10.0)),
      ((10.0, 10.0), (10.0, 0.0)), ((10.0, 0.0), (2.5, 2.5)))),
    Figure("Exagon", Seq(((3.0, 0.0), (7.0, 0.0)), ((7.0, 0.0), (10.0, 5.0)), ((10.0, 5.0), (7.0, 10.0)),
      ((7.0, 10.0), (3.0, 10.0)), ((3.0, 10.0), (0.0, 5.0)), ((0.0, 5.0), (3.0, 0.0)))))

  val points = Seq((5.0, 5.0), (5.0, 8.0), (-10.0, 5.0), (0.0, 5.0), (10.0, 5.0), (8.0, 5.0), (10.0, 10.0))

  println("points: " + points)
  for (f <- figures) {
    println("figure: " + f.name)
    println("        " + f.edges)
    println("result: " + (points map f.contains))
  }

  private implicit def to_edge(p: ((Double, Double), (Double, Double))): Edge = Edge(p._1, p._2)
}