![JAR search and dependency download from the Maven repository](/logo.png)
de.sciss.lucre.geom.IntDistanceMeasure3D.scala Maven / Gradle / Ivy
/*
* DistanceMeasure3D.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
package geom
object IntDistanceMeasure3D {
import IntSpace.ThreeDim
import ThreeDim.{PointLike, HyperCube => Cube3D}
import Space.{bigZero => Zero}
import DistanceMeasure.Ops
private type Sqr = BigInt
private type ML = DistanceMeasure[Long, ThreeDim] with Ops[Long, ThreeDim]
private type MS = DistanceMeasure[Sqr, ThreeDim] with Ops[Sqr, ThreeDim]
private val MaxDistance: Sqr = {
val n = BigInt(Long.MaxValue)
n * n
}
/**
* A measure that uses the euclidean squared distance
* which is faster than the euclidean distance as the square root
* does not need to be taken.
*/
val euclideanSq: MS = EuclideanSq
/**
* A chebychev distance measure, based on the maximum of the absolute
* distances across the first two dimensions. The 3rd dimension is ignored!
*/
val chebyshevXY: ML = ChebyshevXY
/**
* An 'inverted' chebychev distance measure, based on the *minimum* of the absolute
* distances across the first two dimensions. The 3rd dimension is ignored!
* This is, strictly speaking, only a semi metric.
*/
val vehsybehcXY: ML = VehsybehcXY
private object EuclideanSq extends SqrImpl {
override def toString = "IntDistanceMeasure3D.euclideanSq"
def distance (a: PointLike, b: PointLike) = b.distanceSq (a)
def minDistance(a: PointLike, b: Cube3D) = b.minDistanceSq(a)
def maxDistance(a: PointLike, b: Cube3D) = b.maxDistanceSq(a)
}
private sealed trait ClipLike[M] extends DistanceMeasure[M, ThreeDim] {
protected def underlying: DistanceMeasure[M, ThreeDim]
protected def clipping: Cube3D
def distance (a: PointLike, b: PointLike): M = if (clipping.contains(b)) underlying.distance (a, b) else maxValue
def minDistance(a: PointLike, b: Cube3D): M = if (clipping.contains(b)) underlying.minDistance(a, b) else maxValue
def maxDistance(a: PointLike, b: Cube3D): M = if (clipping.contains(b)) underlying.maxDistance(a, b) else maxValue
}
private final class SqrClip(protected val underlying: SqrImpl, protected val clipping: Cube3D)
extends ClipLike[BigInt] with SqrImpl
private final class LongClip(protected val underlying: LongImpl, protected val clipping: Cube3D)
extends ClipLike[Long] with LongImpl
private sealed trait ApproximateLike[M] extends Impl[M] {
protected def underlying: DistanceMeasure[M, ThreeDim]
protected def thresh: M
def minDistance(a: PointLike, b: Cube3D): M = underlying.minDistance(a, b)
def maxDistance(a: PointLike, b: Cube3D): M = underlying.maxDistance(a, b)
def distance(a: PointLike, b: PointLike): M = {
val res = underlying.distance(a, b) // b.distanceSq( a )
if (isMeasureGreater(res, thresh)) res else zeroValue
}
}
private final class SqrApproximate(protected val underlying: SqrImpl, protected val thresh: Sqr)
extends ApproximateLike[Sqr] with SqrImpl
private final class LongApproximate(protected val underlying: LongImpl, protected val thresh: Long)
extends ApproximateLike[Long] with LongImpl
private sealed trait OrthantLike[M]
extends DistanceMeasure[M, ThreeDim] {
protected def underlying: DistanceMeasure[M, ThreeDim]
protected def idx: Int
private val right = (idx & 1) != 0
private val bottom = (idx & 2) != 0
private val back = (idx & 4) != 0
override def toString = underlying.toString + ".quadrant(" + idx + ")"
def distance(a: PointLike, b: PointLike): M = {
if ((if (right ) b.x >= a.x else b.x <= a.x) &&
(if (bottom) b.y >= a.y else b.y <= a.y) &&
(if (back ) b.z >= a.z else b.z <= a.z)) {
underlying.distance(a, b)
} else maxValue
}
def minDistance(p: PointLike, q: Cube3D): M = {
val qe = q.extent
val qem1 = qe - 1
if ((if (right ) (q.cx + qem1) >= p.x else (q.cx - qe) <= p.x) &&
(if (bottom) (q.cy + qem1) >= p.y else (q.cy - qe) <= p.y) &&
(if (back ) (q.cz + qem1) >= p.z else (q.cz - qe) <= p.z)) {
underlying.minDistance(p, q)
} else maxValue
}
def maxDistance( p: PointLike, q: Cube3D ) : M = {
val qe = q.extent
val qem1 = qe - 1
if ((if (right ) (q.cx - qe) >= p.x else (q.cx + qem1) <= p.x) &&
(if (bottom) (q.cy - qe) >= p.y else (q.cy + qem1) <= p.y) &&
(if (back ) (q.cz - qe) >= p.z else (q.cz + qem1) <= p.z)) {
underlying.maxDistance(p, q)
} else maxValue
}
}
private final class SqrOrthant(protected val underlying: DistanceMeasure[BigInt, ThreeDim], protected val idx: Int)
extends OrthantLike[BigInt] with SqrImpl
private final class LongOrthant(protected val underlying: DistanceMeasure[Long, ThreeDim], protected val idx: Int)
extends OrthantLike[Long] with LongImpl
private sealed trait ExceptOrthantLike[M]
extends DistanceMeasure[M, ThreeDim] {
protected def underlying: DistanceMeasure[M, ThreeDim]
protected def idx: Int
private val right = (idx & 1) != 0
private val bottom = (idx & 2) != 0
private val back = (idx & 4) != 0
override def toString = underlying.toString + ".exceptQuadrant(" + idx + ")"
def distance(a: PointLike, b: PointLike): M = {
if ((if (right ) b.x <= a.x else b.x >= a.x) ||
(if (bottom) b.y <= a.y else b.y >= a.y) ||
(if (back ) b.z <= a.z else b.z >= a.z)) {
underlying.distance(a, b)
} else maxValue
}
def minDistance(p: PointLike, q: Cube3D): M = {
val qe = q.extent
val qem1 = qe - 1
if ((if (right ) (q.cx - qe) <= p.x else (q.cx + qem1) >= p.x) ||
(if (bottom) (q.cy - qe) <= p.y else (q.cy + qem1) >= p.y) ||
(if (back ) (q.cz - qe) <= p.z else (q.cz + qem1) >= p.z)) {
underlying.minDistance(p, q)
} else maxValue
}
def maxDistance(p: PointLike, q: Cube3D): M = {
val qe = q.extent
val qem1 = qe - 1
if ((if (right ) (q.cx + qem1) <= p.x else (q.cx - qe) >= p.x) ||
(if (bottom) (q.cy + qem1) <= p.y else (q.cy - qe) >= p.y) ||
(if (back ) (q.cz + qem1) <= p.z else (q.cz - qe) >= p.z)) {
underlying.maxDistance(p, q)
} else maxValue
}
}
private final class SqrExceptOrthant(protected val underlying: DistanceMeasure[BigInt, ThreeDim], protected val idx: Int)
extends OrthantLike[BigInt] with SqrImpl
private final class LongExceptOrthant(protected val underlying: DistanceMeasure[Long, ThreeDim], protected val idx: Int)
extends OrthantLike[Long] with LongImpl
private object ChebyshevXY extends ChebyshevXYLike {
override def toString = "IntDistanceMeasure3D.chebyshevXY"
protected def apply (dx: Long, dy: Long): Long = math.max(dx, dy) // math.min(dx, dy) // math.max(dx, dy)
protected def applyMin(dx: Long, dy: Long): Long = math.max(dx, dy) // math.min(dx, dy)
protected def applyMax(dx: Long, dy: Long): Long = math.max(dx, dy)
}
private object VehsybehcXY extends ChebyshevXYLike {
override def toString = "IntDistanceMeasure3D.vehsybehcXY"
protected def apply (dx: Long, dy: Long): Long = math.min(dx, dy)
protected def applyMin(dx: Long, dy: Long): Long = math.min(dx, dy)
protected def applyMax(dx: Long, dy: Long): Long = math.min(dx, dy) // math.min(dx, dy)
}
private sealed trait ChebyshevXYLike extends LongImpl {
protected def apply (dx: Long, dy: Long): Long
protected def applyMin(dx: Long, dy: Long): Long
protected def applyMax(dx: Long, dy: Long): Long
def distance(a: PointLike, b: PointLike): Long = {
val dx = math.abs(a.x.toLong - b.x.toLong)
val dy = math.abs(a.y.toLong - b.y.toLong)
apply(dx, dy)
}
def minDistance(a: PointLike, q: Cube3D): Long = {
val px = a.x
val py = a.y
val qe = q.extent
val qem1 = qe - 1
val qcx = q.cx
val qcy = q.cy
val l = qcx - qe // q.left
val t = qcy - qe // q.top
var dx = 0L
var dy = 0L
if (px < l) {
dx = l.toLong - px.toLong
if (py < t) {
dy = t.toLong - py.toLong
} else {
val b = qcy + qem1 // q.bottom
if (py > b) {
dy = py.toLong - b.toLong
}
}
} else {
val r = qcx + qem1 // q.right
if (px > r) {
dx = px.toLong - r.toLong
if (py < t) {
dy = t.toLong - py.toLong
} else {
val b = qcy + qem1 // q.bottom
if (py > b) {
dy = py.toLong - b.toLong
}
}
} else if (py < t) {
dy = t.toLong - py.toLong
if (px < l) {
dx = l.toLong - px.toLong
} else {
if (px > r) {
dx = px.toLong - r.toLong
}
}
} else {
val b = qcy + qem1 // q.bottom
if (py > b) {
dy = py.toLong - b.toLong
if (px < l) {
dx = l.toLong - px.toLong
} else {
if (px > r) {
dx = px.toLong - r.toLong
}
}
}
}
}
applyMin(dx, dy)
}
def maxDistance( a: PointLike, q: Cube3D ) : Long = {
val px = a.x
val py = a.y
val qcx = q.cx
val qcy = q.cy
val qe = q.extent
val qem1 = qe - 1
if (px < qcx) {
val dx = (qcx + qem1).toLong - px.toLong
val dy = if (py < qcy) {
// bottom right is furthest
(qcy + qem1).toLong - py.toLong
} else {
// top right is furthest
py.toLong - (qcy - qe).toLong
}
apply(dx, dy)
} else {
val dx = px.toLong - (qcx - qe).toLong
val dy = if (py < qcy) {
// bottom left is furthest
(qcy + qem1).toLong - py.toLong
} else {
// top left is furthest
py.toLong - (qcy - qe).toLong
}
applyMax(dx, dy)
}
}
}
sealed trait Impl[M] extends Ops[M, ThreeDim] {
protected def zeroValue: M
// TODO XXX WARNING: this is probably faulty
override def stabbingDirections(v: PointLike, parent: Cube3D, child: Cube3D): List[Int] = {
val vx = v.x
val vy = v.y
val pl = parent.left
val pt = parent.top
val pr = parent.right
val pbm = parent.bottom
val pf = parent.front
val pbk = parent.back
if (vx < pl) {
// require(child.left == pl, s"v = $v, parent = $parent, child = $child")
if (child.top == pt) {
if (child.front == pf) {
0 :: Nil // only expanding to the right is relevant
} else if (child.back == pbk) {
4 :: Nil
} else {
0 :: 4 :: Nil
}
} else if (child.bottom == pbm) {
if (child.front == pf) {
2 :: Nil // only expanding to the right is relevant
} else if (child.back == pbk) {
6 :: Nil
} else {
2 :: 6 :: Nil
}
} else { // v is left to parent
if (child.front == pf) {
0 :: 2 :: Nil
} else if (child.back == pbk) {
4 :: 6 :: Nil
} else {
0 :: 2 :: 4 :: 6 :: Nil
}
}
} else if (vx > pr) {
// require(child.right == pr, s"v = $v, parent = $parent, child = $child")
if (child.top == pt) {
if (child.front == pf) {
1 :: Nil // only expanding to the left is relevant
} else if (child.back == pbk) {
5 :: Nil
} else {
1 :: 5 :: Nil
}
} else if (child.bottom == pbm) {
if (child.front == pf) {
3 :: Nil // only expanding to the left is relevant
} else if (child.back == pbk) {
7 :: Nil
} else {
3 :: 7 :: Nil
}
} else { // v is left to parent
if (child.front == pf) {
1 :: 3 :: Nil
} else if (child.back == pbk) {
5 :: 7 :: Nil
} else {
1 :: 3 :: 5 :: 7 :: Nil
}
}
} else {
if (vy < pt) { // v outside of parent, to its top
// require(child.top == pt, s"v = $v, parent = $parent, child = $child")
if (child.left == pl) {
if (child.front == pf) {
0 :: Nil
} else if (child.back == pbk) {
4 :: Nil
} else {
0 :: 4 :: Nil
}
} else if (child.right == pr) {
if (child.front == pf) {
1 :: Nil
} else if (child.back == pbk) {
5 :: Nil
} else {
1 :: 5 :: Nil
}
} else {
if (child.front == pf) {
0 :: 1 :: Nil
} else if (child.back == pbk) {
4 :: 5 :: Nil
} else {
0 :: 1 :: 4 :: 5 :: Nil
}
}
} else if (vy > pbm) { // v outside of parent, to its bottom
// require(child.bottom == pb, s"v = $v, parent = $parent, child = $child")
if (child.left == pl) {
if (child.front == pf) {
2 :: Nil
} else if (child.back == pbk) {
6 :: Nil
} else {
2 :: 6 :: Nil
}
} else if (child.right == pr) {
if (child.front == pf) {
3 :: Nil
} else if (child.back == pbk) {
7 :: Nil
} else {
3 :: 7 :: Nil
}
} else {
if (child.front == pf) {
2 :: 3 :: Nil
} else if (child.back == pbk) {
6 :: 7 :: Nil
} else {
2 :: 3 :: 6 :: 7 :: Nil
}
}
} else { // v is inside parent
if (child.left == pl) {
if (child.top == pt) {
if (child.front == pf) {
0 :: Nil
} else if (child.back == pbk) {
4 :: Nil
} else {
0 :: 4 :: Nil
}
} else if (child.bottom == pbm) {
if (child.front == pf) {
2 :: Nil
} else if (child.back == pbk) {
6 :: Nil
} else {
2 :: 6 :: Nil
}
} else {
if (child.front == pf) {
0 :: 2 :: Nil
} else if (child.back == pbk) {
4 :: 6 :: Nil
} else {
0 :: 2 :: 4 :: 6 :: Nil
}
}
} else if (child.right == pr) {
if (child.top == pt) {
if (child.front == pf) {
1 :: Nil
} else if (child.back == pbk) {
5 :: Nil
} else {
1 :: 5 :: Nil
}
} else if (child.bottom == pbm) {
if (child.front == pf) {
3 :: Nil
} else if (child.back == pbk) {
7 :: Nil
} else {
3 :: 7 :: Nil
}
} else {
if (child.front == pf) {
1 :: 3 :: Nil
} else if (child.back == pbk) {
5 :: 7 :: Nil
} else {
1 :: 3 :: 5 :: 7 :: Nil
}
}
} else {
if (child.top == pt) {
if (child.front == pf) {
0 :: 1 :: Nil
} else if (child.back == pbk) {
4 :: 5 :: Nil
} else {
0 :: 1 :: 4 :: 5 :: Nil
}
} else if (child.bottom == pbm) {
if (child.front == pf) {
2 :: 3 :: Nil
} else if (child.back == pbk) {
6 :: 7 :: Nil
} else {
2 :: 3 :: 6 :: 7 :: Nil
}
} else {
if (child.front == pf) {
0 :: 1 :: 2 :: 3 :: Nil
} else if (child.back == pbk) {
4 :: 5 :: 6 :: 7 :: Nil
} else {
0 :: 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: Nil
}
}
}
}
}
}
}
trait SqrImpl extends Impl[Sqr] {
// final val manifest : Manifest[ BigInt ] = Manifest.classType[ BigInt ]( classOf[ BigInt ])
final def newArray(size: Int) = new Array[BigInt](size)
final def maxValue : Sqr = MaxDistance
final def zeroValue: Sqr = Zero
final def isMeasureZero (m: BigInt): Boolean = m == Zero
final def isMeasureGreater(a: BigInt, b: BigInt): Boolean = a > b
final def compareMeasure(a: BigInt, b: BigInt): Int = if (a > b) 1 else if (a < b) -1 else 0
final def clip(quad: Cube3D): MS = new SqrClip(this, quad)
final def approximate(thresh: BigInt): MS = new SqrApproximate(this, thresh)
final def orthant(idx: Int): MS = {
require(idx >= 0 && idx < 8, "Orthant index out of range (" + idx + ")")
new SqrOrthant(this, idx)
}
final def exceptOrthant(idx: Int): MS = {
require(idx >= 0 && idx < 8, "Orthant index out of range (" + idx + ")")
new SqrExceptOrthant(this, idx)
}
}
trait LongImpl extends Impl[Long] {
// final def manifest : Manifest[ Long ] = Manifest.Long
final def newArray(size: Int) = new Array[Long](size)
final def maxValue : Long = Long.MaxValue
final def zeroValue: Long = 0L
final def isMeasureZero (m: Long): Boolean = m == 0L
final def isMeasureGreater(a: Long, b: Long): Boolean = a > b
final def compareMeasure(a: Long, b: Long): Int = if (a > b) 1 else if (a < b) -1 else 0
final def clip (quad: Cube3D): ML = new LongClip (this, quad )
final def approximate(thresh: Long) : ML = new LongApproximate(this, thresh)
final def orthant(idx: Int): ML = {
require(idx >= 0 && idx < 8, "Orthant index out of range (" + idx + ")")
new LongOrthant(this, idx)
}
final def exceptOrthant(idx: Int): ML = {
require(idx >= 0 && idx < 8, "Orthant index out of range (" + idx + ")")
new LongExceptOrthant(this, idx)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy