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

de.sciss.lucre.geom.IntHyperCubeN.scala Maven / Gradle / Ivy

/*
 *  IntHyperCubeN.scala
 *  (LucreData)
 *
 *  Copyright (c) 2011-2014 Hanns Holger Rutz. All rights reserved.
 *
 *  This software is published under the GNU Lesser General Public License v2.1+
 *
 *
 *  For further information, please contact Hanns Holger Rutz at
 *  [email protected]
 */

package de.sciss.lucre.geom

import collection.immutable.{IndexedSeq => Vec}
import IntSpace.NDim

sealed trait IntHyperCubeNLike extends HyperCube[NDim] with QueryShape[BigInt, NDim] {
  import Space.bigZero

  def dim: Int

  def center(idx: Int): Int

  /** The extent is the half side length of the cube */
  def extent: Int

  final def orthant(idx: Int): NDim#HyperCube = {
    val e = extent >> 1
    val d = Vector.tabulate(dim)(i => if ((idx & (1 << i)) == 0) -e else e)
    IntHyperCubeN(d, e)
  }

  final def contains(point: NDim#PointLike): Boolean = {
    val em1 = extent - 1
    var i = 0; while (i < dim) {
      val cc = center(i)
      val pc = point(i)
      if (cc - extent > pc || cc + em1 < pc) return false
      i += 1
    }
    true
  }

  final def contains(cube: NDim#HyperCube): Boolean = {
    val be    = cube.extent
    val bem1  = be - 1
    val em1   = extent - 1

    var i = 0; while (i < dim) {
      val bcc = cube.center(i)
      val cc = center(i)
      if (bcc - be < cc - extent || bcc + bem1 > cc + em1) return false
      i += 1
    }
    true
  }

  final def area: BigInt = {
    val s = extent.toLong << 1
    BigInt(s).pow(dim)
  }

  // -- QueryShape --

  final def overlapArea(b: NDim#HyperCube): BigInt = {
    val be    = b.extent
    val bem1  = be - 1
    val em1   = extent - 1
    var prod  = Space.bigOne

    var i = 0; while (i < dim) {
      val bcc = b.center(i)
      val cc = center(i)
      val min = math.max(cc - extent, bcc - be).toLong
      val max = math.min(cc + em1, bcc + bem1).toLong
      val delta = max - min + 1
      if (delta <= 0L) return bigZero
      prod *= delta
      i += 1
    }

    prod
  }

  final def isAreaGreater(a: NDim#HyperCube, b: BigInt): Boolean = a.area > b

  final def isAreaNonEmpty(area: BigInt): Boolean = area > bigZero

  final def minDistance(point: NDim#PointLike): Double =
    math.sqrt(minDistanceSq(point).toDouble) // or use this: http://www.merriampark.com/bigsqrt.htm ?

  final def maxDistance(point: NDim#PointLike): Double =
    math.sqrt(maxDistanceSq(point).toDouble)

  /** The squared (euclidean) distance of the closest of the cube's corners
    * or sides to the point, if the point is outside the cube,
    * or zero, if the point is contained
    */
  final def minDistanceSq(point: NDim#PointLike): BigInt = {
    val em1     = extent - 1
    var sumSqr  = bigZero

    var i = 0; while (i < dim) {
      val ac = point(i)
      val cc = center(i)
      val delta = if (ac < cc) {
        val min = cc - extent
        if (ac < min) min - ac else 0
      } else {
        val max = cc + em1
        if (ac > max) ac - max else 0
      }
      sumSqr += delta * delta
      i += 1
    }

    sumSqr
  }

  /** Calculates the maximum squared euclidean
    * distance to a point in the euclidean metric.
    * This is the distance (squared) to the corner which is the furthest from
    * the `point`, no matter if it lies within the hyper-cube or not.
    */
  final def maxDistanceSq(point: NDim#PointLike): BigInt = {
    val em1     = extent - 1
    var sumSqr  = bigZero

    var i = 0;
    while (i < dim) {
      val cc = center(i)
      val ac = point(i)
      val acl = ac.toLong
      val delta = if (ac < cc) {
        (cc + em1).toLong - acl
      } else {
        acl - (cc - extent).toLong
      }
      sumSqr += delta * delta
      i += 1
    }

    sumSqr
  }

  final def indexOf( a: NDim#PointLike ) : Int = {
    val em1 = extent - 1
    var res = 0

    var i = 0; while (i < dim) {
      val ac = a(i)
      val cc = center(i)
      val pos = if (ac < cc) {
        if (ac >= cc - extent) 0 else return -1
      } else {
        if (ac <= cc + em1) 1 << i else return -1
      }
      res |= pos
      i += 1
    }

    res
  }

  final def indexOf(b: NDim#HyperCube): Int = {
    val be    = b.extent
    val bem1  = be - 1
    val em1   = extent - 1
    var res   = 0

    var i = 0; while (i < dim) {
      val bcc = b.center(i)
      val cc = center(i)
      val bmin = bcc - be
      val bmax = bcc + bem1
      val pos = if (bcc < cc) {
        // not particular elegant to return in an assignment, but well, it's allowed :)
        if (bmin >= cc - extent && bmax < cc) 0 else return -1
      } else {
        // right?
        if (bmin >= cc && bmax <= cc + em1) 1 << i else return -1
      }
      res |= pos
      i += 1
    }

    res
  }

  final def greatestInteresting(a: NDim#PointLike, b: NDim#PointLike): NDim#HyperCube = gi(a.components, 1, b)

  final def greatestInteresting(a: NDim#HyperCube, b: NDim#PointLike): NDim#HyperCube = {
    val ae = a.extent
    val ac = a.components.map(_ - ae)
    gi(ac, ae << 1, b)
  }

  private def gi(a: Vec[Int], asize: Int, b: NDim#PointLike): NDim#HyperCube = {
    var mmc = Int.MaxValue
    var mi  = Int.MaxValue
    var i = 0; while (i < dim) {
      val cc  = center(i)
      val tlc = cc - extent
      val ac  = a(i)
      val akc = ac - tlc
      val bkc = b(i) - tlc
      val mc  = if (akc <= bkc) {
        IntSpace.binSplit(akc + asize, bkc)
      } else {
        IntSpace.binSplit(bkc + 1, akc)
      }
      if (mc <= mmc) {
        mmc = mc
        mi  = i

      }
      i += 1
    }

    val components = Vector.tabulate(dim) { i =>
      val cc  = center(i)
      val tlc = cc - extent
      val ac  = a(i)
      val akc = ac - tlc
      val bkc = b(i) - tlc
      if (i != mi) {
        val c0 = math.min(akc, bkc)
        tlc + (c0 & (mmc << 1)) - mmc
      } else {
        // the coarsest dimension
        val c2 = math.max(akc, bkc)
        tlc + (c2 & mmc)
      }
    }

    IntHyperCubeN(components, -mmc)
  }
}

object IntHyperCubeN {
  implicit def serializer = IntSpace.NDim.hyperCubeSerializer
}
final case class IntHyperCubeN(components: Vec[Int], extent: Int) extends IntHyperCubeNLike {
  def center(idx: Int): Int = components(idx)

  def dim: Int = components.size
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy