mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-11 06:11:50 +09:00
138 lines
4.3 KiB
Kotlin
138 lines
4.3 KiB
Kotlin
package net.torvald.aa
|
|
|
|
import net.torvald.terrarum.Point2d
|
|
import net.torvald.terrarum.gameactors.ActorWBMovable
|
|
import net.torvald.terrarum.sqr
|
|
|
|
/**
|
|
* k-d Tree that uses binary heap instead of binary tree to improve data locality
|
|
*
|
|
*
|
|
* -- I couldn't observe any significant boost in performance but this one seems
|
|
* to give 3-4 more frames per second.
|
|
*
|
|
* Created by minjaesong on 2017-01-02.
|
|
*
|
|
*
|
|
* Remarks:
|
|
* - NOT using the fullCodePage with 2x2 mode makes it slower... skewed tree generation?
|
|
*/
|
|
class KDHeapifiedTree() {
|
|
|
|
private val dimension = 2
|
|
private val initialSize = 128
|
|
private val nodes = Array<ActorWBMovable?>(initialSize, { null })
|
|
|
|
private val root: Int = 0
|
|
|
|
fun findNearest(query: Point2d) =
|
|
getNearest(root, query, 0).get()!!
|
|
|
|
private fun Int.get() = nodes[this]?.feetPosPoint
|
|
private fun Int.getActor() = nodes[this]
|
|
private fun Int.getLeft() = this * 2 + 1
|
|
private fun Int.getRight() = this * 2 + 2
|
|
private fun Int.set(value: ActorWBMovable?) { nodes[this] = value }
|
|
private fun Int.setLeftChild(value: ActorWBMovable?) { nodes[this.getLeft()] = value }
|
|
private fun Int.setRightChild(value: ActorWBMovable?) { nodes[this.getRight()] = value }
|
|
|
|
private val zeroPoint = Point2d(0.0, 0.0)
|
|
|
|
private fun create(points: List<ActorWBMovable?>, depth: Int, index: Int): ActorWBMovable? {
|
|
if (points.isEmpty()) {
|
|
index.set(null)
|
|
|
|
return null
|
|
}
|
|
else {
|
|
val items = points.sortedBy {
|
|
if (it != null) it.feetPosPoint[depth % dimension]
|
|
else Double.POSITIVE_INFINITY
|
|
}
|
|
val halfItems = items.size shr 1
|
|
|
|
index.setLeftChild(create(items.subList(0, halfItems), depth + 1, index.getLeft()))
|
|
index.setRightChild(create(items.subList(halfItems + 1, items.size), depth + 1, index.getRight()))
|
|
index.set(items[halfItems])
|
|
|
|
return index.getActor()
|
|
}
|
|
}
|
|
|
|
private fun getNearest(currentNode: Int, query: Point2d, depth: Int): Int {
|
|
//println("depth, $depth")
|
|
|
|
val direction = currentNode.compare(query, depth % dimension)
|
|
|
|
val next = if (direction < 0) currentNode.getLeft() else currentNode.getRight()
|
|
val other = if (direction < 0) currentNode.getRight() else currentNode.getLeft()
|
|
var best = if (next.get() == null)
|
|
currentNode
|
|
else
|
|
getNearest(next, query, depth + 1) // traverse to leaf
|
|
|
|
if (currentNode.get()!!.distSqr(query) < best.get()!!.distSqr(query)) {
|
|
best = currentNode
|
|
}
|
|
|
|
if (other.get() != null) {
|
|
if (currentNode.get()!!.dimDistSqr(query, depth % dimension) < best.get()!!.distSqr(query)) {
|
|
val bestCandidate = getNearest(other, query, depth + 1)
|
|
if (bestCandidate.get()!!.distSqr(query) < best.get()!!.distSqr(query)) {
|
|
best = bestCandidate
|
|
}
|
|
}
|
|
}
|
|
|
|
return best // work back up
|
|
}
|
|
|
|
private fun expandArray() {
|
|
val prevNodes = nodes.copyOf()
|
|
Array<ActorWBMovable?>(prevNodes.size * 2, { null })
|
|
create(prevNodes.toList(), 0, 0)
|
|
}
|
|
|
|
fun Int.compare(other: Point2d, dimension: Int) =
|
|
other[dimension] - this.get()!![dimension]
|
|
|
|
private fun Point2d.dimDistSqr(other: Point2d, dimension: Int) =
|
|
other[dimension].minus(this[dimension]).sqr()
|
|
|
|
private operator fun Point2d.get(index: Int) = if (index == 0) this.x else this.y
|
|
}
|
|
|
|
fun intLog2(number: Int): Int {
|
|
var number = number
|
|
if (number == 0) return 0
|
|
var log = 0
|
|
if (number and 0xffff0000.toInt() != 0) {
|
|
number = number ushr 16
|
|
log = 16
|
|
}
|
|
if (number >= 256) {
|
|
number = number ushr 8
|
|
log += 8
|
|
}
|
|
if (number >= 16) {
|
|
number = number ushr 4
|
|
log += 4
|
|
}
|
|
if (number >= 4) {
|
|
number = number ushr 2
|
|
log += 2
|
|
}
|
|
return log + number.ushr(1)
|
|
}
|
|
|
|
fun nextPowerOfTwo(number: Int): Int {
|
|
var number = number - 1
|
|
number = number or (number shr 1)
|
|
number = number or (number shr 2)
|
|
number = number or (number shr 4)
|
|
number = number or (number shr 8)
|
|
number = number or (number shr 16)
|
|
number++
|
|
number += if (number == 0) 1 else 0
|
|
return number
|
|
} |